Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
Шрифт:
• «Сервер принимает (receives) сообщение от клиента»;
• «Сервер отвечает (replies) клиенту».
Я преднамеренно использовал именно эти выражения, потому что они в точности соответствуют действительным именам функций, которые используются для передачи сообщений в QNX/Neutrino.
Ниже приводится (в алфавитном порядке) полный список функций QNX/Neutrino, относящихся к обмену сообщениями:
• ChannelCreate, ChannelDestroy;
• ConnectAttach, ConnectDetach;
• MsgDeliverEvent;
• MsgError;
• MsgRead, MsgReadv;
• MsgRecieve, MsgRecievePulse, MsgRecievev;
• MsgReply, MsgReplyv;
• MsgSend, MsgSendc, MsgSendsv, MsgSendsvnc, MsgSendvs, MsgSendvsnc, MsgSendv, MsgSendvnc;
• MsgWrite, MsgWritev.
Пусть
Разобьем обсуждение на две части: отдельно обсудим функции, которые применяются на стороне клиента, и отдельно — те, что применяются на стороне сервера.
Клиент
Клиент, который желает послать запрос серверу, блокируется до тех пор, пока сервер не завершит обработку запроса. Затем, после завершения сервером обработки запроса, клиент разблокируется, чтобы принять «ответ».
Это подразумевает обеспечение двух условий: клиент должен «уметь» сначала установить соединение с сервером, а потом обмениваться с ним данными с помощью сообщений — как в одну сторону (запрос — «send»), так и в другую (ответ — «reply»).
Итак, рассмотрим теперь функции по порядку. Первое, что мы должны сделать — это установить соединение. Это мы сделаем с помощью функции ConnectAttach, описанной следующим образом:
Функции ConnectAttach передаются три идентификатора: идентификатор nd — дескриптор узла (Node Descriptor),
Вместе эти три идентификатора, которые обычно записываются в виде «ND/PID/CHID», однозначно идентифицируют сервер, с которым клиент желает соединиться. Аргументы index и flags мы здесь просто проигнорируем (установим их в ноль).
Итак, предположим, что мы хотим подсоединиться к процессу, находящемуся на нашем узле и имеющего идентификатор 77, по каналу с идентификатором 1. Ниже приведен пример программы для выполнения этого:
Можно видеть, что присвоением идентификатору узла (nd) нулевого значения мы сообщаем ядру о том, что мы желаем установить соединение на локальном узле.
С этого момента у меня есть идентификатор соединения — небольшое целое число, которое однозначно идентифицирует соединение моего клиента с конкретным сервером по заданному каналу.
Я смогу применять этот идентификатор для отправки запросов серверу сколько угодно раз. Выполнив все, для чего предназначалось соединение, я смогу уничтожить его с помощью функции:
Итак, давайте рассмотрим, как я воспользуюсь этим на практике.
Передача сообщения со стороны клиента осуществляется применением какой-либо функции из семейства MsgSend*.
Мы рассмотрим это на примере простейшей из них — MsgSend:
Аргументами функции MsgSend являются :
• идентификатор соединения с целевым сервером (coid);
• указатель на передаваемое сообщение (smsg);
• размер передаваемого сообщения (sbytes);
• указатель на буфер для ответного сообщения (rmsg);
• размер ответного сообщения (rbytes);
Что может быть проще!
Передадим сообщение процессу с идентификатором 77 по каналу 1: