Чтение онлайн

ЖАНРЫ

QNX/UNIX: Анатомия параллелизма
Шрифт:

if (!(NameServer = name_attach(NULL, "MyService", NAME_FLAG_ATTACH_GLOBAL)))

return EXIT_FAILURE;

Флаг

NAME_FLAG_ATTACH_GLOBAL
указывает, что приложение-сервер объявляет свое имя глобально — в сети. Приложение, которое может подсоединить службу глобально, должно иметь право доступа
root
. После выполнения этого вызова в директории
/dev/name/global
появится подсоединенное имя
MyService
(если бы третий аргумент вызова
был установлен в ноль, это имя оказалось бы подсоединенным к
/dev/name/local
и было бы доступно только локально).

Регистрируя имя в пространстве глобальных имен, функция

name_attach
создает канал, идентификатор которого она возвращает в составе структуры
NameServer
. Отметим, что этот канал создается с определенными установленными флагами, задающими соответствующие действия системе:

_NTO_CHF_UNBLOCK
— доставлять владельцу канала импульс с кодом
_PULSE_CODE_UNBLOCK
и значением
rcvid
каждый раз, когда Reply-блокированный клиент попытается разблокироваться (скажем, по получению сигнала или по таймеру);

_NTO_CHF_DISCONNECT
— доставлять владельцу канала импульс с кодом
_PULSE_CODE_DISCONNECT
, когда от процесса отсоединились все установленные соединения клиента (клиент выполнил
name_close
на каждый свой
name_open
к имени сервера либо вообще умер);

_NTO_CHF_COID_DISCONNECT
— доставлять владельцу канала импульс с кодом
_PULSE_CODE_COIDDEATH
и значением
coid
(идентификатора соединения) для каждого соединения по этому каналу, когда канал закрывается.

Теперь, после создания канала, сервер может становиться на прием сообщений от клиентов:

rcvid = MsgReceive(NameServer->chid, &MsgBuf, sizeof MsgBuf);

Однако может так случиться, что клиент пошлет не непосредственное сообщение для сервера, а выполнит, скажем, чтение, что, по сути, тоже является отосланным сообщением. Поэтому при получении сообщений необходимо производить их «фильтрацию»:

if (MsgBuf.hdr_type >= _IO_BASE && Buffer.hdr.type <= _IO_MAX) {

MsgError(rcvid, ENOSYS);

continue;

}

Получив от клиента некое предопределенное сообщение, сервер сбрасывает флаг

flagWork
и выходит из петли ожидания сообщений, тем самым завершая свою работу.

С учетом этих деталей и организован нижеописанный сервер.

Код процесса-сервера, использующего службу глобальных имен

#include <stdio.h>

#include <errno.h>

#include <stdlib.h>

#include <sys/dispatch h>

/*
На сервер могут приходить и импульсы. Как минимум. */

typedef struct _pulse msg_header_t;

/* Структура сообщения состоит из заголовка и буфера наших данных */

typedef struct _MsgBuf {

msg_header_t hdr;

char* Buffer;

} MsgBuf_t;

int main {

name_attach_t* NameServer;

MsgBuf_t MsgBuf;

int rcvid;

char BufReply[100];

int flagWork = 1;

/* Создаем глобальное имя /dev/name/global/MyService */

if (!(NameServer = name_attach(NULL, "MyService",

NAME_FLAG_ATTACH_GLOBAL)))

return EXIT_FAILURE;

/* Становимся на петлю получения сообщений */

while (flgWork) {

if ((rcvid = MsgReceive(NameServer->chid, &MsgBuf,

sizeof MsgBuf, NULL)) == -1) {

printf("Ошибка при получении сервером MyService "

"сообщения от клиента\n");

fflush(stdout);

break;

}

if (!rcvid) {

// Получен импульс

switch(MsgBuf.hdr.code) {

case _PULSE_CODE_DISCONNECT:

/* Поскольку для канала установлен флаг _NTO_CHF_DISCONNECT, ядро

автоматически не освобождает связи, установленные клиентом ранее.

Сервер должен выполнить это со своей стороны сам, "сознательно"

удалив маршрут от себя обратно к клиенту */

ConnectDetach(MsgBuf.hdr.scoid);

break;

case _PULSE_CODE_UNBLOCK;

/* Клиент пытается разблокироваться, не дождавшись ответа по Reply. Надо

выполнить какие-то действия, чтобы корректно (для себя)

обработать эту ситуацию, и все-таки отпустить этого клиента - ему

ведь надо! При этом импульсе в MsgBuf.hdr.value приходит rcvid */

MsgReply(MsgBuf.hdr.value.sival_int, EAGAIN, NULL, 0);

break;

Поделиться с друзьями: