Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
- Название:Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
- Автор:
- Жанр:
- Издательство:Петрополис
- Год:2001
- Город:Санкт-Петербург
- ISBN:5-94656-025-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform краткое содержание
Книга "Введение в QNX/Neutrino 2» откроет перед вами в мельчайших подробностях все секреты ОСРВ нового поколения от компании QNX Software Systems Ltd (QSSL) — QNX/Neutrino 2. Книга написана в непринужденной манере, легким для чтения и понимания стилем, и поможет любому, от начинающих программистов до опытных системотехников, получить необходимые начальные знания для проектирования надежных систем реального времени, от встраиваемых управляющих приложений до распределенных сетевых вычислительных систем
В книге подробно описаны основные составляющие ОС QNX/Neutrino и их взаимосвязи. В частности, уделено особое внимание следующим темам:
• обмен сообщениями: принципы функционирования и основы применения;
• процессы и потоки: базовые концепции, предостережения и рекомендации;
• таймеры: организация периодических событий в программах;
• администраторы ресурсов: все, что относится к программированию драйверов устройств;
• прерывания: рекомендации по эффективной обработке.
В книге представлено множество проверенных примеров кода, подробных разъяснений и рисунков, которые помогут вам детально вникнуть в и излагаемый материал. Примеры кода и обновления к ним также можно найти на веб-сайте автора данной книги, www.parse.com.
Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Применение обмена сообщениями
Теперь, когда мы рассмотрели базовые концепции обмена сообщениями и выяснили, что он используется даже в таких обычных повседневных вещах как библиотека языка Си, давайте рассмотрим кое-какие детали.
Мы рассуждали о «клиентах» и «серверах». Я также использовал три ключевые выражения:
• «Клиент посылает (sends) сообщение серверу»;
• «Сервер принимает (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() .
Пусть вас не приводит в замешательство размер списка функций. Вы запросто сможете писать приложения «клиент/сервер», используя лишь небольшое подмножество этого списка, просто по мере углубления в детали вы поймете, что некоторые из вышеперечисленных функций могут оказаться очень полезными в определенных случаях.
Минимальный полезный набор функций включает в себя функции ChannelCreate() , ConnectAttach() , MsgReply() , MsgSend() и MsgRecieve() .
Разобьем обсуждение на две части: отдельно обсудим функции, которые применяются на стороне клиента, и отдельно — те, что применяются на стороне сервера.
Клиент
Клиент, который желает послать запрос серверу, блокируется до тех пор, пока сервер не завершит обработку запроса. Затем, после завершения сервером обработки запроса, клиент разблокируется, чтобы принять «ответ».
Это подразумевает обеспечение двух условий: клиент должен «уметь» сначала установить соединение с сервером, а потом обмениваться с ним данными с помощью сообщений — как в одну сторону (запрос — «send»), так и в другую (ответ — «reply»).
Итак, рассмотрим теперь функции по порядку. Первое, что мы должны сделать — это установить соединение. Это мы сделаем с помощью функции ConnectAttach() , описанной следующим образом:
#include
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? К этому мы скоро вернемся (см. ниже «Поиск сервера по ND/PID/CHID»).
С этого момента у меня есть идентификатор соединения — небольшое целое число, которое однозначно идентифицирует соединение моего клиента с конкретным сервером по заданному каналу.
Я смогу применять этот идентификатор для отправки запросов серверу сколько угодно раз. Выполнив все, для чего предназначалось соединение, я смогу уничтожить его с помощью функции:
ConnectDetach(coid);
Итак, давайте рассмотрим, как я воспользуюсь этим на практике.
Передача сообщения со стороны клиента осуществляется применением какой-либо функции из семейства MsgSend*() .
Мы рассмотрим это на примере простейшей из них — MsgSend() :
#include
int MsgSend(int coid, const void *smsg, int sbytes,
void *rmsg, int rbytes);
Аргументами функции MsgSend() являются :
• идентификатор соединения с целевым сервером ( coid );
• указатель на передаваемое сообщение ( smsg );
• размер передаваемого сообщения ( sbytes );
• указатель на буфер для ответного сообщения ( rmsg );
• размер ответного сообщения ( rbytes );
Что может быть проще!
Передадим сообщение процессу с идентификатором 77 по каналу 1:
#include
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, "Ошибка MsgSend\n");
perror(NULL);
exit (EXIT_FAILURE);
}
if (strlen(rmsg) > 0) {
printf("Процесс с ID 77 возвратил \"%s\"\n", rmsg);
}
Предположим, что процесс с идентификатором 77 был действительно активным сервером, ожидающим сообщение именно такого формата по каналу с идентификатором 1. После приема сообщения сервер обрабатывает его и в некоторый момент времени выдает ответ с результатами обработки. В этот момент функция MsgSend() должна возвратить ноль (0), указывая этим, что все прошло успешно. Если бы сервер послал нам в ответ какие-то данные, мы смогли бы вывести их на экран с помощью последней строки в программе (с тем предположением, что обратно мы получаем корректную ASCIIZ-строку).
Сервер
Теперь, когда мы рассмотрели клиента, перейдем к серверу. Клиент использовал функцию ConnectAttach() для создания соединения с сервером, а затем использовал функцию MsgSend() для передачи сообщений.
Под этим подразумевается, что сервер должен создать канал — то, к чему присоединялся клиент, когда вызывал функцию ConnectAttach() . Обычно сервер, однажды создав канал, приберегает его «впрок».
Канал создается с помощью функции ChannelCreate() и уничтожается с помощью функции ChannelDestroy() :
#include
int ChannelCreate(unsigned flags);
int ChannelDestroy(int chid);
Мы еще вернемся к обсуждению аргумента flags (в разделе «Флаги каналов», см. ниже), а покамест будем использовать для него значение 0 (ноль). Таким образом, для создания канала сервер должен сделать так:
Читать дальшеИнтервал:
Закладка: