Читать «UNIX: взаимодействие процессов» онлайн - страница 102

Уильям Ричард Стивенс

Рис. 6.2. Мультиплексирование сообщений между несколькими клиентами и одним сервером

Рассмотрим усложненный вариант: один сервер и несколько клиентов. В этом случае можно использовать значение типа 1, например, для обозначения сообщений от любого клиента серверу. Если клиент передаст серверу свой идентификатор процесса в качестве части сообщения, сервер сможет отсылать клиенту сообщения, используя его идентификатор в качестве значения типа сообщения. Каждый клиент будет использовать свой PID в качестве аргумента type при вызове msgrcv. На рис. 6.2 приведен пример использования очереди для мультиплексирования этих сообщений между несколькими клиентами и одним сервером.

ПРИМЕЧАНИЕ

При использовании одного канала IPC одновременно клиентами и сервером всегда существует потенциальная возможность зависания (deadlock). Клиенты могут (в этом примере) заполнить очередь своими сообщениями, не давая серверу возможности отправить ответ. В этому случае клиенты заблокируются при вызове msgsnd, как и сервер. Одно из соглашений, исключающих возможность такой взаимной блокировки, заключается в том, что сервер должен всегда отключать блокировку записи в очередь сообщений.

Теперь мы можем переделать наш пример с клиентом и сервером, используя одну очередь сообщений с различными типами для разных адресатов. Эти программы используют следующее соглашение: сообщения с типом 1 адресованы серверу, а все остальные сообщения имеют тип, соответствующий идентификатору процесса адресата. При этом запрос клиента должен содержать его PID вместе с полным именем запрашиваемого файла, аналогично программе в разделе 4.8.

В листинге 6.12 приведен текст функции main сервера. Заголовочный файл svmsg.h был приведен в листинге 6.7. Создается единственная очередь сообщений (если она существует, ошибки не возникнет). Идентификатор этой очереди сообщений используется в качестве обоих аргументов при вызове функции server.

Листинг 6.12. Функция main сервера

//svmsgmpx1q/server_main.с

1  #include "svmsg.h"

2  void server(int, int);

3  int

4  main(int argc, char **argv)

5  {

6   int msqid;

7   msqid = Msgget(MQ_KEY1, SVMSG_MODE | IPC_CREAT);

8   server(msqid, msqid); /* одна очередь в обе стороны */

9   exit(0);

10 }

Функция server обеспечивает работу сервера. Ее текст приведен в листинге 6.13. Эта функция представляет собой комбинацию листинга 4.10 — нашего сервера FIFO, считывавшего команды, состоявшие из идентификатора процесса и полного имени файла, — и листинга 4.16, в котором использовались функции mesg_send и mesg_recv. Обратите внимание, что идентификатор процесса, отправляемый клиентом, используется в качестве типа для всех сообщений, отправляемых сервером этому клиенту. Эта функция представляет собой бесконечный цикл, в котором считываются запросы клиентов и отсылаются запрошенные файлы. Этот сервер является последовательным (см. раздел 4.9).