Главная страница  Взаимодействие нетривиальных процессов 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 [ 50 ] 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

тогда как сообщения сервера клиентам имеют различные значения типов, уникальные для каждого клиента. Естественно, в качестве значения типа сообщения, гарантированно уникального для каждого клиента, можно использовать идентификатор процесса клиента.

2. Поле type может использоваться для установки приоритета сообщений. Это позволяет получателю считывать сообщения в порядке, отличном от обычного для очередей (FIFO). В программных каналах и FIFO данные могли приниматься только в том порядке, в котором они были отправлены. Очереди System V позволяют считывать сообщения в произвольном порядке в зависимости от значений типа сообщений. Более того, можно вызывать msgrcv с флагом IPC NOWAIT для считывания сообщений с конкретным типом и немедленного возвращения управления процессу в случае отсутствия таких сообщений.

Пример: одна очередь на приложение

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

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

сервер

type = 1234 or 9876: ответы сервера

type = 1: запросы клиентов


очередь

известный ключ

клиент 1

клиент 2

PID 9876

PID 1234

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



ПРИМЕЧАНИЕ-

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

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

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

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

svnisgnipxlq/server niain.c

1 #inclucle svmsg.h

2 void serverCint, int);

3 int

4 mainCint argc. char **argv)

6 int msqid;

7 msqid - MsggetСMQ KEY1. SVMSG MODE IPC CREAT):

8 serverCmsqid. msqid); /* одна очередь в обе стороны */

9 exitCO); 10 }

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

в листинге 6.14 приведен текст функции mai п клиента. Клиент открывает очередь сообщений, которая должна была быть создана сервером заранее.

Функция client, текст которой дан в листинге6.15, обеспечивает всю обработку со стороны клиента. Эта функция представляет собой комбинацию про-



грамм из листингов 4.11 и 4.15. В первой программе клиент отсылал свой идентификатор и полное имя файла, а во второй программе использовались функции mesg send и mesg recv. Обратите внимание, что тип сообщений, запрашиваемых функцией mesg recv, совпадает с идентификатором процесса клиента.

Функции с1 lent и server используют функции mesg send и mesg recv из листингов 6.9 и 6.11.

Листинг 6.13. Функция server

svmsgmpxlq/server.c

1 finclude mesg.h

2 void

3 serverCint readfd. int writefd)

5 FILE *fp;

6 char *ptr;

7 pid t pid;

8 ssize t n;

9 struct mymesg mesg;

10 for С : : ) {

11 /* считывание полного имени из канала IPC */

12 mesg.mesg type = 1:

13 if С Cn - Mesg recvCreadfd. &mesg)) == 0) {

14 err msgС pathname missing );

15 continue;

16 }

17 mesg.mesg data[n] = \0; /* полное имя */

18 if С Cptr = strchrCmesg.mesg data, )) == NULL) {

19 err msgC bogus request: s . mesg.mesg data);

20 continue:

21 }

22 *ptr++ =0: /* ptr = полное имя */

23 pid = atolCmesg.mesg data):

24 mesg.mesg type = pid: /* для обратных сообщений */

25 if С Cfp = fopenCptr. г )) == NULL) {

26 /* 4еггог: must tell client */

27 snprintfCmesg.mesg data + n. sizeofCmesg.mesg data) - n.

28 ; cant open, s\n , strerrorCerrno)):

29 mesg, mesgjen = strlenCptr):

30 memmoveCmesg,mesg data. ptr. mesg.mesgjen);

31 Mesg sendCwritefd. &mesg):

32 } else {

33 /* файл открыт, копируем клиенту */

34 while CFgetsCmesg,mesg data, MAXMESGDATA, fp) != NULL) {

35 mesg,mesgjen = strlenCmesg,mesg data);

36 Mesg sendСwritefd, &mesg);

37 }

38 FcloseCfp):

39 }

40 /* сообщение нулевой длины заканчивает связь */

41 mesg.mesgjen = 0: продолжение



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 [ 50 ] 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

© 2000 - 2024 ULTRASONEX-AMFODENT.RU.
Копирование материалов разрешено исключительно при условии цититирования.