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

ЖАНРЫ

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

Кёртен Роб

Шрифт:

 printf("Процесс с ID 77 возвратил \"%s\"\n", rmsg);

}

Предположим, что процесс с идентификатором 77 был действительно активным сервером, ожидающим сообщение именно такого формата по каналу с идентификатором 1. После приема сообщения сервер обрабатывает его и в некоторый момент времени выдает ответ с результатами обработки. В этот момент функция MsgSend должна возвратить ноль (0), указывая этим, что все прошло успешно. Если бы сервер послал нам в ответ какие-то данные, мы смогли бы вывести их на экран с помощью последней строки в программе (с тем предположением, что обратно мы получаем корректную ASCIIZ-строку).

Сервер

Теперь,

когда мы рассмотрели клиента, перейдем к серверу. Клиент использовал функцию ConnectAttach для создания соединения с сервером, а затем использовал функцию MsgSend для передачи сообщений.

Создание канала

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

Канал создается с помощью функции ChannelCreate и уничтожается с помощью функции ChannelDestroy:

#include <sys/neutrino.h>

int ChannelCreate(unsigned flags);

int ChannelDestroy(int chid);

Мы еще вернемся к обсуждению аргумента flags (в разделе «Флаги каналов», см. ниже), а покамест будем использовать для него значение 0 (ноль). Таким образом, для создания канала сервер должен сделать так:

int chid;

chid = ChannelCreate(0);

Теперь у нас есть канал. В этом пункте клиенты могут подсоединиться (с помощью функции ConnectAttach) к этому каналу и начать передачу сообщений:

Связь между каналом сервера и клиентским соединением.

Обработка сообщений

В терминах обмена сообщениями, сервер отрабатывает схему обмена в два этапа — этап «приема» (receive) и этап «ответа» (reply).

Взаимосвязь функций клиента и сервера при обмене сообщениями.

Обсудим сначала два простейших варианта соответствующих функций, MsgReceive и MsgReply, а далее посмотрим, какие есть варианты.

#include <sys/neutrino.h>

int MsgReceive(int chid, void *rmsg, int rbytes,

 struct _msg_info *info);

int MsgReply(int rcvid, int status, const void *msg,

 int nbytes);

Посмотрим, как соотносятся параметры:

Поток данных при обмене сообщениями.

Как видно из рисунка, имеются четыре элемента, которые мы должны обсудить:

1. Клиент вызывает функцию MsgSend и указывает ей на буфер передачи (указателем smsg и длиной sbytes). Данные передаются в буфер функции MsgReceive на стороне сервера, по адресу rmsg

и длиной rbytes. Клиент блокируется.

2. Функция MsgReceive сервера разблокируется и возвращает идентификатор отправителя rcvid, который будет впоследствии использован для ответа. Теперь сервер может использовать полученные от клиента данные.

3. Сервер завершил обработку сообщения и теперь использует идентификатор отправителя rcvid, полученный от функции MsgReceive, передавая его функции MsgReply. Заметьте, что местоположение данных для передачи функции MsgReply задается как указатель на буфер (smsg) определенного размера (sbytes). Ядро передает данные клиенту.

4. Наконец, ядро передает параметр sts, который используется функцией MsgSend клиента как возвращаемое значение. После этого клиент разблокируется.

Вы, возможно, заметили, что для каждой буферной передачи указываются два размера (в случае запроса от клиента клиента это sbytes на стороне клиента и rbytes на стороне сервера; в случае ответа сервера это sbytes на стороне сервера и rbytes на стороне клиента). Это сделано для того, чтобы разработчики каждого компонента смогли определить размеры своих буферов — из соображений дополнительной безопасности.

В нашем примере размер буфера функции MsgSend совпадал с длиной строки сообщения. Давайте теперь рассмотрим, что происходит в сервере и как размер используется там.

Структура сервера

Вот общая структура сервера:

#include <sys/neutrino.h>

...

void server(void) {

 int rcvid; // Указывает, кому надо отвечать

 int chid; // Идентификатор канала

 char message[512]; // Достаточно велик

 // Создать канал

 chid = ChannelCreate(0);

 // Выполняться вечно — для сервера это обычное дело

 while (1) {

// Получить и вывести сообщение

rcvid = MsgReceive(chid, message, sizeof(message), NULL);

printf("Получил сообщение, rcvid %X\n", rcvid);

printf("Сообщение такое: \"%s\".\n", message);

// Подготовить ответ — используем тот же буфер

strcpy(message, "Это ответ");

MsgReply(rcvid, EOK, message, sizeof(message));

 }

}

Как видно из программы, функция MsgReceive сообщает ядру о том, что она может обрабатывать сообщения размером вплоть до

sizeof(message)
(или 512 байт). Наш клиент (представленный выше) передал только 28 байт (длина строки). На приведенном ниже рисунке это и показано:

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