printf('Ребенок: дитятко работу закончило
');
ChannelDestroy(CChanid);
ConnectDetach(coid);
return(0);
}
Обмен сообщениями на основе менеджера ресурсов
Описанный выше способ построения функционирующей в сети системы процессов может быть реализован далеко не всегда. Зачастую клиенту не известна полная триада, позволяющая ему создать соединение с сервером. Вспомним, что в QNX 4, где для создания связи с другим процессом был необходим его идентификатор, существовала служба пространства имен, обеспечиваемая сервером службы nameloc
. Сервер объявлял свое имя в пространстве имен с помощью функции qnx_name_attach()
, а затем клиент, вызвав функцию qnx_name_locate()
, получал от системы идентификатор сервера, по которому мог далее с ним общаться.
Разработчики QNX 6 настоятельно рекомендуют вместо использования службы имен выполнять сервер в виде менеджера ресурсов, причем настолько настоятельно, что до версии 6.3 аналог этой службы — менеджер службы глобальных имен gns
— функционировал только локально. И надо признать, что мощь и изящество менеджера ресурсов являются очень убедительным подкреплением этих рекомендаций.
При использовании механизма менеджера ресурсов процесс, выступающий в качестве сервера, регистрирует свой так называемый префикс путевого имени файла в пространстве файловых имен, после чего другие процессы (клиенты) могут открывать это имя как файл, используя стандартную библиотечную функцию open()
. Получив в результате выполнения этой функции дескриптор файла, они затем могут обращаться к серверу, используя стандартные библиотечные функции С, такие как read ()
, write()
и т.д.
Однако важным (по крайней мере, для программистов, не желающих отказываться от такого привычного и эффективного механизма передачи данных, как обмен сообщениями) является тот факт, что этот дескриптор на самом деле является не чем иным, как идентификатором соединения. И поэтому к серверу можно обращаться не только через высокоуровневые функции работы с файлами, но и с помощью элементарных функций обмена сообщениями MsgSend*()
(элементарных, напомню, в том смысле, что в действительности все стандартные высокоуровневые функции работы с файлами реализованы через функции обмена сообщениями).
Вместе с тем следует учитывать, что менеджер ресурсов поставляется для программиста фактически в готовом виде — как шкаф, то есть уже имеются все отделения, полки, ножки, дверцы, и задача разработчика - лишь заполнить его своим содержимым. Однако «навесить» на него свою полочку уже невозможно. Иными словами, при передаче сообщений с использованием менеджера ресурсов необходимо применять уже имеющиеся средства менеджера ресурсов, благо их вполне достаточно.
Самым очевидным и наиболее простым способом передачи сообщений к серверу является инкапсуляция сообщений в «сообщения управления устройством» — сообщения типа devctl()
. Однако этот способ имеет существенный недостаток, заключающийся в том, что при взаимном обмене данными между сервером и клиентом, что является более общим и достаточно частым случаем, мы вынуждены передавать в обоих направлениях буферы одинаковой длины. Это объясняется тем, что функция devctl()
имеет только один параметр для размеров обоих буферов. Поэтому в качестве универсального средства передачи сообщений применение этой функции выглядит непривлекательным.
К радости разработчиков, менеджер ресурсов предлагает функцию приватных сообщений io_msg()
для сообщений типа _IO_MSG
. Менеджер способен их обрабатывать после соответствующей «настройки», заключающейся в подключении диапазона сообщений, интерпретируемых как приватные (допустимые значения должны быть больше 0x1ff
— диапазона, резервируемого за системой). При этом сервер в состоянии как сразу «отпустить» Reply- блокированного клиента, так и оставить его в этом состоянии до нужного момента.
Ниже приводится код процесса-клиента и процесса-сервера. Последний представляет собой стандартный менеджер ресурсов — в таком виде, в каком он, так сказать, поставляется разработчику. Единственная шляпа, помещаемая в этот шкаф, — это обработчик приватных сообщений. Здесь вы и должны поместить специфический код обработки принятого сообщения.
В остальном все достаточно тривиально. Более подробно о том, как писать менеджеры ресурсов, можно прочитать в главе «Writing a Resource Manager» технической документации QNX, а также в книгах [1] и [4] (глава Олега Цилюрика «Драйверы»).
Пример обмена сообщениями с помощью менеджера ресурсов
Код файла заголовков
#define NET_OPER '/net/904-3'
#define NET_REG '/net/Bed-Test'
// Максимальная длина обычного стандартного сообщения.
#define MESSIZE_MAX 100
// Максимальная длина инвентаризационного имени процесса
#define PROC_NAME_MAX 100
struct IdLabel_t { // Структура, содержащая,
int id; // -.инвентаризационную метку процесса
char name[PROC_NAME_MAX]; // - инвентаризационное имя процесса
} IdLabel[] = {
/* диапазон выделенный Группе # 1: от 0x5000 до 0x50ff */
0x5001, 'пробный менеджер ресурсов',
0x5002, 'первый тестовый клиент для менеджера ресурсов',
0x5003, 'второй тестовый клиент для менеджера ресурсов',
0x5004, 'третий тестовый клиент для менеджера ресурсов',
0x50ff, 'четвертый тестовый клиент для менеджера ресурсов'
/* диапазон, выделенный Группе # 2: от 0x5100 до 0x51ff */
/* диапазон, выделенный Группе # 3: от 0x5200 до 0x52ff */
};
char Anonymous[] = 'чуждый процесс';
int ALLNUM_MYPROC = sizeof(IdLabel) /
sizeof(IdLabel[0]);