Опора деревянной одностоечной и способы укрепление угловых опор: Опоры ВЛ - конструкции, предназначенные для поддерживания проводов на необходимой высоте над землей, водой...
Семя – орган полового размножения и расселения растений: наружи у семян имеется плотный покров – кожура...
Топ:
Комплексной системы оценки состояния охраны труда на производственном объекте (КСОТ-П): Цели и задачи Комплексной системы оценки состояния охраны труда и определению факторов рисков по охране труда...
Процедура выполнения команд. Рабочий цикл процессора: Функционирование процессора в основном состоит из повторяющихся рабочих циклов, каждый из которых соответствует...
Интересное:
Берегоукрепление оползневых склонов: На прибрежных склонах основной причиной развития оползневых процессов является подмыв водами рек естественных склонов...
Как мы говорим и как мы слушаем: общение можно сравнить с огромным зонтиком, под которым скрыто все...
Влияние предпринимательской среды на эффективное функционирование предприятия: Предпринимательская среда – это совокупность внешних и внутренних факторов, оказывающих влияние на функционирование фирмы...
Дисциплины:
|
из
5.00
|
Заказать работу |
Содержание книги
Поиск на нашем сайте
|
|
|
|
2.3.1 Теория
Архитектура и структура обмена сообщениями
Три ключевые выражения:
· «Клиент посылает (sends) сообщение серверу»;
· «Сервер принимает (receives) сообщение от клиента»;
· «Сервер отвечает (replies) клиенту».
Эти выражения в точности соответствуют действительным именам функций, которые используются для передачи сообщений в QNX/Neutrino.
Минимальный полезный набор функций включает в себя функции ChannelCreateQ, ConnectAttach(), MsgReplyQ, MsgSend() и MsgRecievef).
Разобьем обсуждение на две части: отдельно обсудим функции, которые применяются на стороне клиента, и отдельно — те, что применяются на стороне сервера.
Клиент
Клиент, который желает послать запрос серверу, блокируется до тех пор, пока сервер не завершит обработку запроса. Затем, после завершения сервером обработки, запроса клиент разблокируется, чтобы принять «ответ».
Это подразумевает обеспечение двух условий: клиент должен «уметь» сначала установить соединение с сервером, а потом обмениваться с ним данными с помощью сообщений — как в одну сторону (запрос — «send»), так и в другую (ответ — «reply»).
Установление соединения
Первое, что должны сделать — это установить соединение с помощью функции ConnectAttach(), описанной следующим образом:
#include <sys/neutrino.h>
int ConnectAttach
(int nd,pid_t pid, int chid, unsigned index, int flags);
Функции ConnectAttach() передаются три идентификатора;
· nd— дескриптор узла (Node Descriptor),
· pid— идентификатор процесса (process ID)
· chid — идентификатор канала (channel ID).
Вместе эти три идентификатора, которые обычно записываются в виде «ND/PID/CHID», однозначно идентифицируют сервер, с которым клиент желает соединиться. Аргументы index и flags мы здесь просто проигнорируем (установим их в ноль).
Итак, предположим, что мы хотим подсоединиться к процессу, находящемуся на нашем узле и имеющему идентификатор 77, по каналу с идентификатором 1. Ниже приведен пример программы для выполнения этого:
int coid;
coid = ConnectAttach (0, 77 „ 1, 0, 0);
Можно видеть, что присвоением идентификатору узла (nd) нулевого значения мы сообщаем ядру о том, что мы желаем установить соединение на локальном узле.
Соединиться надо с процессом 77 и по каналу 1.
С этого момента есть идентификатор соединения — небольшое целое число, которое однозначно идентифицирует соединение моего клиента с конкретным сервером по заданному каналу.
Теперь можно применять этот идентификатор для отправки запросов серверу сколько угодно раз. Выполнив все, для чего предназначалось соединение, его можно уничтожить с помощью функции:
ConnectDetach (coid);
Передача сообщений (sending)
Передача сообщения со стороны клиента осуществляется применением функции MsgSend(). Мы рассмотрим это на примере:
#include <sys/neutrino.h>
int MsgSend (int coid,
const void *smsg, int sbytes, void *rmsg, int rbytes);
Аргументами функции MsgSendQ являются:
· идентификатор соединения с целевым сервером (coid);
· указатель на передаваемое сообщение (smsg);
· размер передаваемого сообщения (sbytes);
· указатель на буфер для ответного сообщения (rmsg);
· размер ответного сообщения (rbytes).
Передадим сообщение процессу с идентификатором 77 по каналу 1:
#include <sys/neutrino.h>
char *smsg = «Это буфер вывода»; char rmsg [200]; int coid;
// Установить соединение
coid = ConnectAttach (0, 77, 1, 0, 0);
if (coid == -1) {
fprintf (stderr, «Ошибка ConnectAttach к 0/77/1!\n»);
perror (NULL);
exit (EXIT_FAILURE);
// Послать сообщение
if(MsgSend(coid, smsg,strlen (smsg) + 1,rmsg,sizeof(rmsg)) == -1)
{ fprintf (stderr, «Ошибка MsgSendXn»);
perror (NULL);
exit (EXIT_FAILURE);
if (strlen (rmsg) > 0)
{
printf («Процесс с ID 77 возвратил \«%s\»\n», rmsg);
}
Предположим, что процесс с идентификатором 77 был действительно активным сервером, ожидающим сообщение именно такого формата по каналу с идентификатором 1. После приема сообщения сервер обрабатывает его и в некоторый момент времени выдает ответ с результатами обработки. В этот момент функция MsgSendQ должна возвратить ноль (0), указывая этим, что все прошло успешно. Если бы сервер послал нам в ответ какие-то данные, мы смогли бы вывести их на экран с помощью последней строки в программе.
Сервер. Создание канала
Сервер должен создать канал — то, к чему присоединялся клиент, когда вызывал функцию ConnectAttach(). Обычно сервер, однажды создав канал, приберегает его «впрок».
Канал создается с помощью функции ChannelCreate() и уничтожается с помощью функции ChannelDestroyQ:
#include <sys/neutrino.h>
int ChannelCreate (unsigned flags);
int ChannelDestroy (int chid);
Таким образом, для создания канала сервер должен сделать так:
int chid;
chid = ChannelCreate (0);
Теперь у нас есть канал. В этом пункте клиенты могут подсоединиться (с помощью функции ConnectAttachQ) к этому каналу и начать передачу сообщений:

Рисунок 3 Связь между каналом сервера и клиентским соединением.
Обработка сообщений
В терминах обмена сообщениями, сервер отрабатывает схему обмена
в два этапа:
· этап «приема» (receive);
· этап «ответа» (reply).

Рисунок 4 Взаимосвязь функций клиента и сервера при обмене сообщениями.
Обсудим два простейших варианта соответствующих функций, MsgReceiveQ и 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). Данные передаются в буфер функции MsgReceiveQ на стороне сервера, по адресу rmsg и длиной rbytes. Клиент блокируется.
2 Функция MsgReceiveQ сервера разблокируется и возвращает идентификатор отправителя rcvid, который будет впоследствии использован для ответа. Теперь сервер может использовать полученные от клиента данные.
3 Сервер завершил обработку сообщения и теперь использует идентификатор отправителя rcvid, полученный от функции MsgReceiveQ, передавая его функции MsgReply(). Заметьте, что местоположение данных для передачи функции MsgReply() задается как указатель на буфер (smsg) определенного размера (sbytes). Ядро передает данные клиенту.
4 Наконец, ядро передает параметр sts, который используется функцией MsgSend() клиента как возвращаемое значение. После этого клиент разблокируется.
Для каждой буферной передачи указываются два размера (в случае запроса от клиента клиента это sbytes на стороне клиента и rbytes на стороне сервера; в случае ответа сервера это sbytes на стороне сервера и rbytes на стороне клиента). Это сделано для того, чтобы разработчики каждого компонента смогли определить размеры своих буферов — из соображений дополнительной безопасности.
2.3.2 Текст программы
// server.c
#include <stdio.h>
#include <pthread.h>
#include <inttypes.h>
#include <errno.h>
#include <sys/neutrino.h>
void server(void)
{
int rcvid; //Ykazivaet komy nado otvechat
int chid; //Identifikator kanala
char message[512]; //
printf("Server start working \n");
chid=ChannelCreate(0); //Sozdanie Kanala
printf("Chanel id: %d \n", chid);
printf("Pid: %d \n", getpid());
// vipolniaetsa vechno- dlia servera eto normalno
while(1)
{
// Polychit i vivesti soobshenie
rcvid=MsgReceive(chid,message,sizeof(message), NULL);
printf("Polychili soobshenie, rcvid %X \n",rcvid);
printf("Soobshenie takoe: \"%s\". \n", message);
// Podgotovit otvet
strcpy(message,"Eto otvet");
MsgReply(rcvid, EOK, message, sizeof(message));
printf("\"%s\". \n", message);
}
}
int main(void)
{
printf("Prog server \n");
server();
sleep(5);
return(1);
}
//client.c
#include <stdio.h>
#include <pthread.h>
#include <inttypes.h>
#include <errno.h>
#include <sys/neutrino.h>
int main(void)
{
char smsg[20];
char rmsg[200];
int coid;
long serv_pid;
printf("Prog client, Vvedite PID servera \n");
scanf ("%ld",&serv_pid);
printf("Vveli %ld \n", serv_pid);
coid=ConnectAttach(0,serv_pid,1,0,0);
printf("Connect res %d \n, vvedite soobshenie ", coid);
scanf("%s",&smsg);
printf("Vveli %s \n", smsg);
if(MsgSend(coid,smsg,strlen(smsg)+1,rmsg, sizeof(rmsg))==-1)
{
printf("Error MsgSend \n");
}
return(1);
}
2.3.3 Последовательность действий
После компиляции программ сервера и клиента у нас будет 2 исполняемых файла. Назовём их server и client соответственно.
Программу server необходимо запустить в фоновом режиме # server &. Она начнёт работать: создаст канал, выведет номер канала и идентификатор процесса сервера, будет ждать сообщения от клиента.
Потом необходимо запустить клиента. Он попросит ввести идентификатор процесса сервера, для установления соединения с ним, и само сообщение (20 символов). Далее можно наблюдать, как сервер получит сообщение, выведет его и пошлёт ответ.
На этом клиент закончит свою работу, но его можно запустить ещё раз и послать другое сообщение.
Остановить работу сервера можно функцией kill < идентификатор процесса сервера >.
2.3.4 Результаты
# `pwd`/server &
[3] 2019364
# Prog server
Server start working
Chanel id: 1
Pid: 2019364
# `pwd`/client
Prog client, Vvedite PID servera
2019364
Vveli 2019364
Connect res 3
, vvedite soobshenie Hello_server
Vveli Hello_server
Polychili soobshenie, rcvid 2
Soobshenie takoe: "Hello_server".
"Eto otvet".
# `pwd`/client
Prog client, Vvedite PID servera
2019364
Vveli 2019364
Connect res 3
, vvedite soobshenie I_snova_Privet
Vveli I_snova_Privet
Polychili soobshenie, rcvid 2
Soobshenie takoe: "I_snova_Privet".
"Eto otvet".
# kill 2019364
#
|
|
|
Своеобразие русской архитектуры: Основной материал – дерево – быстрота постройки, но недолговечность и необходимость деления...
Биохимия спиртового брожения: Основу технологии получения пива составляет спиртовое брожение, - при котором сахар превращается...
История создания датчика движения: Первый прибор для обнаружения движения был изобретен немецким физиком Генрихом Герцем...
Типы оградительных сооружений в морском порту: По расположению оградительных сооружений в плане различают волноломы, обе оконечности...
© cyberpediasu.com 2017-2026 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!