18 if ((ptr = strchr(mesg.mesg_data, ' ')) == NULL) {
19 err_msg("bogus request: %s", mesg.mesg_data);
20 continue;
21 }
22 *ptr++ =0; /* ptr = полное имя */
23 pid = atol(mesg.mesg_data);
24 mesg.mesg_type = pid; /* для обратных сообщений */
25 if ((fp = fopen(ptr, "r")) == NULL) {
26 /* 4error: must tell client */
27 snprintf(mesg.mesg_data + n, sizeof(mesg.mesg_data) – n,
28 ": can't open. %s\n", strerror(errno));
29 mesg.mesg_len – strlen(ptr);
30 memmove(mesg.mesg_data, ptr, mesg.mesg_len);
31 Mesg_send(writefd, &mesg);
32 } else {
33 /* файл открыт, копируем клиенту */
34 while (Fgets(mesg.mesg_data, MAXMESGDATA, fp) != NULL) {
35 mesg.mesg_len = strlen(mesg.mesg_data);
36 Mesg_send(writefd, &mesg);
37 }
38 Fclose(fp);
39 }
40 /* сообщение нулевой длины заканчивает связь */
41 mesg.mesg_len = 0;
42 Mesg_send(writefd, &mesg);
43 }
44 }
//svmsgmpx1q/client_main.c
1 #include "svmsg.h"
2 void client(int, int);
3 int
4 main(int argc, char **argv)
5 {
6 int msqid;
7 /* сервер должен был создать очередь */
8 msqid = Msgget(MQ_KEY1, 0);
9 client(msqid, msqid); /* одна очередь в обе стороны */
10 exit(0);
11 }
//svmsgmpx1q/client.с
1 #include "mesg.h"
2 void
3 client(int readfd, int writefd)
4 {
5 size_t len;
6 ssize_t n;
7 char *ptr;
8 struct mymesg mesg;
9 /* инициализируем буфер идентификатором процесса и пробелом */
10 snprintf(mesg.mesg_data, MAXMESGDATA. "%ld ", (long) getpid());
11 len = strlen(mesg.mesg_data);
12 ptr = mesg.mesg_data + len;
13 /* считываем полное имя файла */
14 Fgets(ptr, MAXMESGDATA – len, stdin);
15 len = strlen(mesg.mesg_data);
16 if (mesg.mesg_data[len-1] == '\n')
17 len--; /* удаляем перевод строки fgets() */
18 mesg.mesg_len = len;
19 mesg.mesg_type = 1;
20 /* записываем PID и имя файла в канал IPC */
21 Mesg_send(writefd, &mesg);
22 /* считываем из канала IPC, записываем в stdout */
23 mesg.mesg_type = getpid();
24 while ((n = Mesg_recv(readfd, &mesg)) > 0)
25 Write(STDOUT_FILENO, mesg.mesg_data, n);
26 }
Изменим теперь предыдущий пример таким образом, чтобы все запросы клиентов передавались по одной очереди, но для отправки ответов использовалась бы отдельная очередь для каждого клиента. На рис. 6.3 изображена схема такого приложения.
Рис. 6.3. Одна очередь для сервера и по одной для каждого клиента
Ключ очереди сервера должен быть известен клиентам, а сами клиенты создают свои очереди с ключом IPC_PRIVATE. Вместо передачи серверу идентификатора процесса клиенты сообщают ему идентификатор своей очереди, в которую сервер направляет свой ответ. Этот сервер является параллельным: для каждого нового клиента порождается отдельный процесс.