Код процесса-сервера (менеджера ресурсов)

Код процесса-сервера (менеджера ресурсов)

Для запуска сервера на удаленном узле выполните с терминала команду:

# on -f /net/Bed-Test /net/904-3/home/ZZZ/BIN/TestMGR

где Bed-Test — имя удаленного узла, 904-3 — имя локального узла, /home/ZZZ/BIN/TestMGR — путь к исполняемому файлу.

Вначале сервер выполняет действия по своей инициализации, специфические для данного процесса. Если они завершились успешно, т.е. сервер готов обслуживать клиентов, он инициализирует себя как администратор устройства (функции dispatch_create(), memset(&resmgr_attr, ...), iofunc_func_init(), resmgr_attach(), message_attach(), dispatch_context_alloc()), при этом на том узле, где запущен менеджер, появляется файл /dev/MESSTEST/RM. После этого, если все прошло успешно, сервер выходит на бесконечную петлю приема сообщений.

Прием сообщений осуществляется функцией dispatch_block(), блокирующей процесс-сервер на ожидании сообщений. При получении сообщения оно передается функции dispatch_handler(), которая производит разборку сообщения. Если это сообщение относится к известным разборщику, оно направляется к соответствующей функции обработки, принимаемой по умолчанию.

Так, в частности, обрабатываются сообщения на открытие ресурса (пересылаемое клиентом при вызове им функции open()), на отсоединение и закрытие ресурса (отсылаются клиентом при вызове им функции close()), на чтение или запись (если клиент вызовет функции read() или write()) и ряд других. Кроме того, разборщику известны сообщения, заголовок которых содержит «инвентаризационную метку», попадающую в диапазон, указанный при вызове функции присоединения приватных сообщений message_attach(). В этом случае сообщение передается для дальнейшей обработки функции-обработчику приватных сообщений (в нашем примере это функция PrivatHandler()).

При рассмотрении функции обработки приватных сообщений PrivatHandler() следует обратить внимание, что, хотя в этой функции и предусмотрено освобождение клиента с Reply-блокировки, она возвращает не _RESMGR_NOREPLY, как можно было бы ожидать, а значение 0, что указывает библиотеке менеджера ресурсов на то, что отвечать Reply-сообщением клиенту уже нет необходимости. Это объясняется тем, что обработчик приватных сообщений сам выполняет Reply-сообщение, и это заложено в нем изначально. В этом состоит важное отличие этого обработчика от всех прочих (взгляните на код обработчика prior_read() в разделе «Менеджеры ресурсов» главы 5).

Еще одна тонкость: при работе с приватными сообщениями в процессе-менеджере необходимо использовать функции диспетчеризации dispatch_*() (dispatch_block(), dispatch_handler() и т.д.), а не функции менеджера ресурсов resmgr_*() (resmgr_block(), resmgr_handler() и т.д.).

#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: невозможно разместить обработчик"

   " диспетчеризации. ", 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: невозможно прикрепить имя менеджера"

   " ресурсов. ", 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("невозможно подключить данный "

   "диапазон приватных сообщений ");

  return(EXIT_FAILURE);

 }

 /* Размещение контекстной структуры */

 ctp = dispatch_context_alloc(dpp);

 /* Размер буфера сообщений, содержащегося а этой структуре, равно как и

    число векторов ввода/вывода, также содержащихся в этой структуре,

    установлены при инициализации структуры атрибутов менеджера ресурсов */

 /* Запуск петли сообщений менеджера ресурсов */

 while(1) {

  // ожидание прихода сообщений

  if ((ctp = dispatch_block(ctp)) == NULL) {

   printf("ошибка блока ");

   return EXIT_FAILURE;

  }

  printf("Менеджер ресурсов получил сообщение"

   " длиной %i байт ", ctp->resmgr_context.info.msglen);

  result = dispatch_handler(ctp);

  // сообщение раскодируется, и на основании заданных таблиц функций связи

  // и ввода/вывода вызывается соответствующая функция обработки сообщения

  if (result)

   printf("Менеджер ресурсов не смог обработать"

    " сообщение result = %i ", result);

 }

}

/********************************************************************

Обработчик приватных сообщений, то есть сообщений, заголовок которых

укладывается в диапазон, указанный при вызове функции message_attach()

********************************************************************/

int PrivatHandler(message_context_t* ctp, int code,

 unsigned flags, void* handle) {

 char Buffer[MESSIZE_MAX];

 printf("получено приватное сообщение тип %x от"

  " "%s" ", code, IdLabelParse(code));

 printf("Вот это сообщение <<%s>> ",

  (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);

}

Данный текст является ознакомительным фрагментом.