QNX/UNIX: Анатомия параллелизма - Олег Цилюрик
Шрифт:
Интервал:
Закладка:
#include <errno.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/iofunc.h>
#include <sys/dispatch.h>
#include <devctl.h>
#include <locale.h>
#include "/home/ZZZ/TESTS/MR/MessTest.h"
int PrivatHandler(message_context_t *ctp, int code,
unsigned flags, void* handle);
char* IdLabelParse(int id);
// Таблица функций связи
static resmgr_connect_funcs_t connect_funcs;
// Таблица функций ввода/вывода
static resmgr_io_funcs_t io_funcs;
// Структура атрибутов устройства
static iofunc_attr_t attr;
main(int args, char **argv) {
resmgr_attr_t resmgr_attr; // Структура атрибутов менеджера ресурсов
dispatch_t *dpp; // Указатель на структуру диспетчеризации,
// содержит идентификатор канала.
dispatch_context_t *ctp; // Контекстная структура; содержит буфер
// сообщений, буфер векторов ввода/вывода
int id;
int result;
char BufferRec[100];
int rcvid;
setlocale(LC_CTYPE, "C-TRADITIONAL");
/* Здесь должны выполняться необходимые действия по инициализации
конкретного сервера */
/* Считаем, что все необходимое теперь выполнено... */
/* Инициализация интерфейса диспетчеризации */
if ((dpp = dispatch_create()) == NULL) {
printf("%s: невозможно разместить обработчик"
" диспетчеризации.n", argv[0]);
return EXIT_FAILURE;
}
/* В результате по адресу dpp создана структура диспетчеризации */
/* Инициализация атрибутов менеджера ресурсов */
memset(&resmgr_attr, 0, sizeof resmgr_attr);
resmgr_attr.nparts_max = 1;
resmgr_attr.msg_max_size = MESSIZE_MAX;
/* Задаем число доступных структур векторов ввода/вывода (IOV) = 1.
Задаем максимальный размер буфера получения равным MESSIZE_MAX.
В результате инициализируются атрибуты менеджера ресурсов */
/* Инициализация функций обработки сообщений */
iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_funcs,
_RESMGR_IO_NFUNCS, &io_funcs);
/* В результате заполняются две таблицы (структуры), задающие функции
обработки для двух специальных типов сообщений:
таблица функций связи и таблица функций ввода/вывода.
В соответствующих местах размещаются принимаемые по умолчанию функции
iofunc_*_default() ... Своими не заменяем - нет необходимости. */
/* Инициализация используемой устройством структуры атрибутов */
iofunc_attr_init(&attr, S_IFNAM | 0666, 0, 0);
attr.nbytes = MESSIZE_MAX + 1;
/* В результате инициализируется структура атрибутов,
используемая устройством;
S_IFNAM указывает, что тип устройства - Special named file,
побитовые флаги определяют права доступа,
число байт в ресурсе задается равным размеру буфера. */
/* Прикрепление имени устройства */
if ((id = resmgr_attach(dpp, &resmgr_attr, "/dev/MESSTEST/RM", _FTYPE_ANY,
0, &connect_funcs, &io_funcs, &attr)) == -1) {
printf("%s: невозможно прикрепить имя менеджера"
" ресурсов.n", argv[0]);
return EXIT_FAILURE;
}
/* Ключевое действие: мы регистрируем на нашем узле имя /dev/MESSTEST/RM
dpp и resmgr_attr - инициализированные выше структуры;
/dev/MESSTEST/RM - ассоциированное с устройством имя,
_FTYPE_ANY - определяет тип открытия устройства (в данном случае
допускается любой тип запроса открытия); равный нулю флаг
разборки пути имени файла определяет, что запрос -
только по имени /dev/MESSTEST/RM,
&connect_funcs - заданные выше подпрограммы связи;
&io_funcs - заданные выше подпрограммы ввода/вывода;
attr - инициализированная выше структура атрибутов устройства.
Подключаем диапазон сообщений, которые должны рассматриваться как
приватные, с передачей их обработчику для таких сообщений -
PrivatHandler() */
if (message_attach(dpp, NULL, 0x5000, 0x5fff, &PrivatHandler, NULL) == -1) {
printf("невозможно подключить данный "
"диапазон приватных сообщенийn");
return(EXIT_FAILURE);
}
/* Размещение контекстной структуры */
ctp = dispatch_context_alloc(dpp);
/* Размер буфера сообщений, содержащегося а этой структуре, равно как и
число векторов ввода/вывода, также содержащихся в этой структуре,
установлены при инициализации структуры атрибутов менеджера ресурсов */
/* Запуск петли сообщений менеджера ресурсов */
while(1) {
// ожидание прихода сообщений
if ((ctp = dispatch_block(ctp)) == NULL) {
printf("ошибка блокаn");
return EXIT_FAILURE;
}
printf("Менеджер ресурсов получил сообщение"
" длиной %i байтn", ctp->resmgr_context.info.msglen);
result = dispatch_handler(ctp);
// сообщение раскодируется, и на основании заданных таблиц функций связи
// и ввода/вывода вызывается соответствующая функция обработки сообщения
if (result)
printf("Менеджер ресурсов не смог обработать"
" сообщение result = %in", result);
}
}
/********************************************************************
Обработчик приватных сообщений, то есть сообщений, заголовок которых
укладывается в диапазон, указанный при вызове функции message_attach()
********************************************************************/
int PrivatHandler(message_context_t* ctp, int code,
unsigned flags, void* handle) {
char Buffer[MESSIZE_MAX];
printf("получено приватное сообщение тип %x от"
" "%s"n", code, IdLabelParse(code));
printf("Вот это сообщение <<%s>>n",
(char *)(ctp->msg) + 4);
strcpy(Buffer, "Клиенту: да, я такой");
MsgReply(ctp->rcvid, EOK, Buffer, sizeof(Buffer));
return(0);
}
/********************************************************************
Функция пользовательской библиотеки, определяющая инвентаризационное
имя процесса по его инвентаризационной метке
********************************************************************/
char* IdLabelParse(int id) {
struct IdLabel_t Inventory;
int i = 0;
while (IdLabel[i].id != id && i < ALLNUM_MYPROC) i++;
if (i == ALLNUM_MYPROC) return Anonymous;
else return(IdLabel[i].name);
}
Использование менеджера службы глобальных имен
Начиная с QNX версии 6.3 сервис глобальных имен, обеспечиваемый GNS-менеджером службы (утилитой gns), действует в сети. Используя этот сервис, нет необходимости организовывать программу как полноценный менеджер ресурсов, при этом приложение-сервер может объявлять свою службу, а приложения-клиенты могут отыскивать и использовать службы через QNET-сеть без знания таких частностей, как, например, где эта служба располагается и кто ее обеспечивает. Подробно о сервисе глобальных имен см. в [4].
Для того чтобы развернуть этот сервис, необходимо в режиме сервера запустить менеджер службы глобальных имен на том узле, где должно работать наше приложение-сервер. В режиме сервера GNS-менеджер выступает в роли некой центральной базы данных, хранящей объявленные службы, и обрабатывает запросы на поиск и установление связи с ними. На узле же, где располагается клиент, запускаем менеджер в режиме клиента, при этом он передает запросы объявления, поиска и установки связи между локальным (то есть расположенным на этом же узле) приложением-клиентом и сервером (серверами) gns.
Серверный узел:
# gns -s
Клиентский узел (узлы):
# gns -с
В результате на узлах, где запущены службы глобальных имен, появятся имена /dev/name/global и /dev/name/local. Каждый узел, на котором запущен gns-клиент или сервер, в одной и той же сети имеет один и тот же вид пространства имен на /dev/name/global. Каждый узел имеет локальное пространство имен /dev/name/local, являющееся локальным для данной машины и отличающееся от локального пространства имен на другой машине. (Кстати, помимо имен global и local под /dev/name/ появится еще имя gns_server или gns_local — имя, под которым регистрируется сам GNS-менеджер.)