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

ЖАНРЫ

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

Кёртен Роб

Шрифт:

Перейдем теперь к клиенту. Изначально клиент работал самостоятельно, пока не решил послать сообщение. Клиент переключается при этом из состояния готовности (READY) в состояние либо блокировки по передаче (send-blocked), либо блокировки по приему (recieve-blocked), в зависимости от состояния сервера, которому было послано сообщение.

Смена состояний клиента

Скорее всего, вам чаще придется иметь дело с состоянием блокировки по приему (reply-blocked), чем с состоянием блокировки по передаче (send-blocked). Состояние блокировки по приему (reply-blocked) реально означает

следующее:

Сервер принял сообщение и теперь обрабатывает его. В некоторый момент времени сервер завершит обработку и ответит клиенту. Клиент блокирован в ожидании этого ответа от сервера.

Сравните с состоянием блокировки по передаче (send-blocked):

Сервер все еще не принял сообщение — вероятно, потому что был занят обработкой другого, ранее поступившего сообщения. Когда сервер возвратится в состояние «приема» вашего (клиентского) сообщения, вы перейдете из состояния блокировки по передаче (send-blocked) в состояние блокировки по ответу (reply- blocked).

На практике, если вы наблюдаете процесс, блокированный по передаче (send-blocked), это означает одно из двух:

1. Вы запечатлели момент, когда сервер был занят обслуживанием некоего клиента и в это время получил еще один запрос.

Это нормальная ситуация — вы можете проверить это, повторно выполнив

pidin
. На сей раз вы, вероятно, сможете увидеть, что этот процесс уже более не блокирован по передаче.

2. В сервере проявилась какая-то внутренняя ошибка, и он больше не воспринимает запросы.

Когда это произойдет, вы сможете увидеть множество процессов, блокированных по передаче на этом сервере. Чтобы проверить это, выполните

pidin
снова и посмотрите, есть ли изменения в состоянии клиентских процессов.

Ниже приведен пример, в котором показан клиент в состоянии блокировки по ответу (reply-blocked) и сервер, по которому он блокирован:

pid tid name prio STATE Blocked

1 1 /nto/x86/sys/procnto 0f READY

1 2 /nto/x86/sys/procnto 10r RECEIVE 1

1 3 /nto/x86/sys/procnto 10r NANOSLEEP

1 4 /nto/x86/sys/procnto 10r RUNNING

1 5 /nto/x86/sys/procnto 15r RECEIVE 1

16426 1 esh 10r REPLY 1

В примере показано, что программа

esh
(встраиваемый командный интерпретатор) передала сообщение процессу с номером 1 (это ядро и администратор процессов,
procnto
) и теперь ждет ответа.

Ну вот, теперь вы знаете основы обмена сообщениями в архитектуре «клиент/сервер».

Не исключено, что вы сейчас думаете: «Так что, получается, чтобы открыть файл или записать данные, мне придется писать специализированные вызовы обмена сообщениями QNX/ Neutrino?!»

Нет, вам не придется программировать обмен сообщениями непосредственно — разве что если вам будет нужно копнуть совсем вглубь (об этом несколько позже). Действительно, позвольте мне показать Вам некоторую программу клиента, который делает передачу сообщений:

#include <fcntl.h>

#include <unistd.h>

int main(void) {

 int fd;

 fd = open("filename", O_WRONLY);

 write(fd, "Это обмен сообщениями\n", 24);

 close(fd);

 return (EXIT_SUCCESS);

}

Видите?

Обычная Си-программа, никаких хитростей.

Собственно обмен сообщениями реализован в Си-библиотеке QNX/Neutrino. Вы просто выдаете вызовы по стандарту POSIX 1003.1 и вызовы функций ANSI Си и Си-библиотека делает за Вас всю работу, связанную с обменом сообщениями.

В приведенном выше примере вызываются три функции, и посылаются три различных сообщения:

• open — передала сообщение «open» («открыть»);

• write — передала сообщение «write» («записать»);

• close — передала сообщение «close» («закрыть»).

Мы обсудим сами сообщения более подробно, когда мы будем изучать администраторы ресурсов (в главе «Администраторы ресурсов»), а пока что единственное, что нам надо знать об этом — это сам факт, что были переданы сообщения различных типов.

Давайте на мгновение отвлечемся и сравним этот подход с тем, как бы это работало в традиционной операционной системе.

Клиентская программа осталась бы такой же — различия были бы скрыты в Си-библиотеке, поставляемой производителем программного обеспечения. В такой системе функция open сделала бы системный вызов, ядро затем обратилось бы непосредственно к файловой системе, которая, в свою очередь, выполнила некоторые действия и возвратила бы дескриптор файла. Вызовы функций write и close работали бы аналогично

Итак? Есть ли преимущества в способе, который предлагает QNX/Neutrino? «Оставайтесь с нами!»

Распределенный обмен сообщениями

Предположим, что мы пожелали изменить приведенный выше пример, чтобы можно было «поговорить» с другим узлом сети. Вы, наверное, думаете, что для этого придется вызывать специальные функции, чтобы «попасть в сеть». Вот сетевой вариант нашей программы:

#include <fcntl.h>

#include <unistd.h>

int main(void) {

 int fd;

 fd = open("/net/wintermute/home/rk/filename", O_WRONLY);

 write(fd, "Это обмен сообщениями\n", 24);

 close(fd);

 return (EXIT_SUCCESS);

}

Вы будете правы, если скажете, что в обеих версиях программы почти одинаковы. Так и есть.

В традиционной ОС функция open библиотеки Си вызывает ядро, которое анализирует имя файла и говорит: «Опа! Это не на нашем узле…» Ядро затем вызывает сетевую файловую систему NFS, которая уже определяет, где в действительности находится файл

/net/wintermute/home/rk/filename
. Затем, NFS вызывает сетевой драйвер и посылает сообщение ядру на узле
wintermute
, которое повторяет весь процесс, описанный нами в нашем первоначальном примере. Заметьте, что в этом случае оказываются вовлеченными две файловые системы, одна из которых — сетевая файловая система (NFS) клиента, а вторая — удаленная. К сожалению, в зависимости от реализации как удаленной файловой системы, так и NFS, некоторые операции (например, блокировки файлов) могут работать некорректно из-за неполной совместимости.

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