27-44 Оставшаяся часть кода пpoгрaммы-cepвepa аналогична функции server из листинга 4.3. Программа открывает файл; если при этом возникает ошибка — клиенту отсылается сообщение о ней. Если открытие файла завершается успешно, его содержимое копируется в канал клиента. После завершения копирования открытый сервером «конец» (дескриптор) канала клиента должен быть закрыт с помощью функции close, чтобы функция read вернула пpoгрaммe-клиeнтy значение 0 (конец файла). Сервер не удаляет канал клиента; клиент должен самостоятельно позаботиться об этом после приема от сервера символа конца файла. Текст пpoгрaммы-клиeнтa приведен в листинге 4.11.
//fifocliserv/mainclient.с
1 #include "fifo.h"
2 int
3 main(int argc, char **argv)
4 {
5 int readfifo, writefifo;
6 size_t len;
7 ssize_t n;
8 char *ptr, fifoname[MAXLINE], buff[MAXLINE];
9 pid_t pid;
10 /* создание FIFO с включением в его имя PID */
11 pid = getpid();
12 snprintf(fifoname, sizeof(fifoname), "/tmp/fifo,%ld", (long) pid):
13 if ((mkfifo(fifoname, FILE_MODE) < 0) && (errno != EEXIST))
14 err_sys("can't create %s", fifoname);
15 /* инициализация буфера PID и пробелом */
16 snprintf(buff, sizeof(buff), "%ld ", (long) pid);
17 len = strlen(buff);
18 ptr = buff + len;
19 /* считывание полного имени */
20 Fgets(ptr, MAXLINE – len, stdin);
21 len = strlen(buff); /* fgets() гарантирует завершающий 0 */
22 /* открытие FIFO сервера и запись в него полного имени и PID */
23 writefifo = Open(SERV_FIFO, O_WRONLY, 0);
24 Write(writefifo, buff, len);
25 /* открытие созданного FIFO; блокирование до открытия его сервером */
26 readfifo = Open(fifoname, O_RDONLY; 0);
27 /* считывание из канала IPC, запись в stdout */
28 while ((n = Read(readfifo, buff, MAXLINE)) > 0)
29 Write(STDOUT_FILENO, buff, n);
30 Close(readfifo);
31 Unlink(fifoname);
32 exit(0);
33 }
10-14 Идентификатор процесса клиента содержится в имени создаваемого им канала.
15-21 Запрос клиента состоит из его идентификатора процесса, одного пробела, полного имени запрашиваемого им файла и символа перевода строки. Строка запроса формируется в массиве buff, причем имя файла считывается из стандартного потока ввода.
22-24 Клиент открывает канал сервера и записывает в него строку запроса. Если клиент окажется первым с момента запуска сервера, вызов open разблокирует сервер, заблокированный после сделанного им вызова open (с флагом O_RDONLY).
25-31 Ответ сервера считывается из канала и записывается в стандартный поток вывода, после чего канал клиента закрывается и* удаляется.
Сервер может быть запущен в одном из окон, а клиент — в другом, и программа будет работать так, как мы и рассчитывали. Ниже мы приводим только текст, выводимый клиентом:
solaris % mainclient /etc/shadow
/etc/shadow: can't open. Permission denied
solaris % mainclient /etc/inet/ntp.conf
multicastclient 224.0.1.1
driftfile /etc/inet/ntp.drift
Мы можем также связаться с сервером из интерпретатора команд, поскольку каналы FIFO обладают именами в файловой системе.
solaris % Pid=$$
solaris % mkfifo /tmp/fifo.$Pid
solaris % echo "$Pid /etc/inet/ntp.conf" > /tmp/fifo.serv
solaris % cat < /tmp/fifo.$Pid
multicastclient 224.0.1.1
driftfile /etc/inet/ntp.drift