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

ЖАНРЫ

Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform

Кёртен Роб

Шрифт:

Модификация будет достаточно проста. Скорее всего, клиентская сторона вызывает функцию, либо возвращающую идентификатор серверного процесса, либо создающую виртуальный канал («VC» — Virtual Circuit) от клиентского узла к удаленному узлу сервера. В обоих случаях как идентификатор процесса, так и идентификатор виртуального канала к удаленному процессу определяются при помощи qnx_name_locate. «Магическим амулетом», связывающим клиента с сервером, здесь является специальная разновидность идентификатора процесса (мы считаем идентификатор виртуального канала идентификатором процесса, поскольку он берется из того же пула номеров и со всех точек зрения выглядит как идентификатор процесса).

Преодолеть основное различие можно было бы, возвращая вместо идентификатора

процесса идентификатор соединения. Поскольку клиент в QNX4, вероятно, не анализирует идентификаторы процессов (да и зачем? Так, просто число), вы могли бы «обмануть» его, применив к «глобальному имени» функцию open. В этом случае, однако, глобальное имя должно было бы быть точкой монтирования, зарегистрированной администратором ресурса в качестве своего «идентификатора». Вот, например, типовой пример клиента QNX4, взятый из моей серверной библиотеки CLID:

/*

 * CLID_Attach(ServerName)

 *

 * Эта подпрограмма отвечает за установление соединения

 * с сервером CLID.

 *

 * Возвращает PID сервера CLID или идентификатор

 * виртуального канала к нему.

*/

// Сюда запишется имя - для других библиотечных вызовов

static char CLID_serverName(MAX_CLID_SERVER_NAME + 1);

// Сюда запишется идентификатор сервера

CLID static int clid_pid = -1;

int CLID_Attach(char *serverName) {

 if (ServerName == NULL) {

sprintf(CLID_serverName, "/PARSE/CLID");

 } else {

strcpy(CLID_serverName, serverName);

 }

 clid_pid = qnx_name_locate(0, CLID_serverName,

sizeof(CLID_ServerIPC), NULL);

 if (clid_pid != -1) {

CLID_IPC(CLID_MsgAttach); // Послать сообщение ATTACH

return (clid_pid);

 }

 return (-1);

}

Вы могли бы изменить это на следующее:

/*

 * CLID_Attach(serverName), версия для QNX/Neutrino

*/

int CLID_Attach(char *serverName) {

 if (ServerName == NULL) {

sprintf(CLID_serverName, "/PARSE/CLID");

 } else {

strcpy(CLID_serverName, serverName);

 }

 return (clid_pid = open(CLID_serverName, O_RDWR));

}

И клиент ничего бы не заметил.

Два замечания по реализации. В качестве зарегистрированного префикса администратора ресурса я просто оставил имя по умолчанию («
/PARSE/CLID
»). Вероятно, лучше было бы взять имя «
/dev/clid
», но насколько вы хотите следовать POSIX — это ваше личное дело. В любом случае, это незначительное изменение, и оно мало связано с тем, что здесь обсуждается.

Второе замечание касается того, что я по-прежнему назвал дескриптор файла clid_pid, хотя

реально ему бы теперь следовало называться clid_fd. Это, опять же, вопрос стиля и касается только того, сколько различий вы хотите иметь между версиями кода для QNX4 и QNX/Neutrino.

В любом случае, того чтобы данная программа была переносима в обе ОС, вам придется выделить код соединения с сервером в отдельную функцию — как я это сделал выше с функцией CLID_Attach.

В какой-то момент клиент должен будет выполнить собственно операцию отправки сообщения. Здесь все становится несколько сложнее. Поскольку отношения клиент/сервер не основаны на отношениях с администраторами ввода/вывода, клиент обычно создает «нестандартные» сообщения. Снова пример из CLID-библиотеки («незащищенный» клиентский вызов здесь — CLID_AddSingleNPANXX, я также включил функции checkAttach и CLID_IPC для того, чтобы продемонстрировать фактическую передачу сообщений и логику проверок):

/*

 * CLID_AddSingleNPANXX(npa, nxx)

*/

int CLID_AddSingleNPANXX(int npa, int nxx) {

 checkAttach;

 CLID_IPCData.npa = npa;

 CLID_IPCData.nxx = nxx;

 CLID_IPC(CLID_MsgAddSingleNPANXX);

 return (CLID_IPCData.returnValue);

}

/*

 * CLID_IPC(номер_сообщения_IPC)

 *

 * Эта подпрограмма вызывает сервер с глобальным буфером

 * CLID_IPCData и заносит в него номер сообщения,

 * переданный ей в качестве аргумента.

 *

 * Если сервера нет, эта подпрограмма установит

 * поле returnValue в CLID_NoServer. Остальные

 * поля остаются как есть.

*/

void CLID_IPC(int IPCMessage) {

 if (clid_pid == -1) {

CLID_IPCData.returnValue = CLID_NoServer;

return;

 }

 CLID_IPCData.serverFunction = IPCMessage;

 CLID_IPCData.type = 0x8001;

 CLID_IPCData.subtype = 0;

 if (Send(clid_pid, &CLID_IPCData, &CLID_IPCData,

sizeof(CLID_IPCData), sizeof(CLID_IPCData))) {

CLID_IPCData.returnValue = CLID_IPCError;

return;

 }

}

void checkAttach {

 if (clid_pid == -1) {

CLID_Attach(NULL);

 }

}

Как вы видите, функция checkAttach применяется для проверки существования соединения с сервером CLID. Если бы соединения не было, это было бы подобно запросу read по несуществующему дескриптору файла. В моем варианте программы функция checkAttach создает соединение автоматически. Это как если бы функция read определила, что дескриптор файла некорректен, и сама создала бы корректный. Еще один вопрос стиля.

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