10 len = strlen(buff); /* fgets() гарантирует завершающий нулевой байт */
11 if (buff[Len-l] ==
12 len--; /* удаление перевода строки из fgets() */
13 /* запись полного имени в канал IPC */
14 Write(writefd, buff, len);
15 /* считывание из канала, вывод в stdout */
16 while ((n = Read(readfd, buff, MAXLINE)) > 0)
17 Write(STDOUT_FILENO, buff, n);
18 }
8-14 Полное имя файла считывается из стандартного потока ввода и записывается в канал после удаления завершающего символа перевода строки, возвращаемого функцией fgets.
15-17 Затем клиент считывает все, что сервер направляет в канал, и записывает эти данные в стандартный поток вывода. Ожидается, что это будет содержимое файла, но в случае его отсутствия будет принято и записано в стандартный поток вывода сообщение об ошибке.
В листинге 4.3 приведена функция server.
//pipe/server.c
1 #include "unpipc.h"
2 void
3 server(int readfd, int writefd)
4 {
5 int fd;
6 ssize_t n;
7 char buff[MAXLINE+1];
8 /* получение полного имени из канала IPC */
9 if ((n = Read(readfd, buff, MAXLINE)) == 0)
10 err_quit("end-of-file while reading pathname"):
11 buff[n] = '\0'; /* полное имя завершается 0 */
12 if ((fd = open(buff, O_RDONLY)) < 0) {
13 /* 4error: must tell client */
14 snprintf(buff + n, sizeof(buff) – n, ": can't open. %s\n".
15 strerror(errno)):
16 n = strlen(buff);
17 Write(writefd, buff, n);
18 } else {
19 /* файл успешно открыт и копируется в канал */
20 while ( (n = Read(fd, buff, MAXLINE)) > 0)
21 Write(writefd, buff, n);
22 Close(fd);
23 }
24 }
8-11 Записанное в канал клиентом имя файла считывается сервером и дополняется завершающим символом с кодом 0 (null-terminated). Обратите внимание, что функция read возвращает данные, как только они помещаются в поток, не ожидая накопления некоторого их количества (MAXLINE в данном примере).
12-17 Файл открывается для чтения и при возникновении ошибки сообщение о ней возвращается клиенту с помощью канала. Для получения строки с соответствующим значению переменной errno сообщением об ошибке вызывается функция strerror (в книге [24, с. 690-691] вы найдете более подробный рассказ об этой функции).
18-23 При успешном завершении работы функции open содержимое файла копируется в канал.
Ниже приведен результат работы программы в случае наличия файла с указанным полным именем и в случае возникновения ошибок:
solaris % mainpipe /etc/inet/ntp.conf
multicastclient 224.0.1.1
driftfile /etc/inet/ntp.drift
solaris % mainpipe /etc/shadow
/etc/shadow: can't open. Permission denied
solaris % mainpipe /no/such/file
/no/such/file: can't open. No such file or directory
4.4. Двусторонние каналы
В предыдущем разделе мы отметили, что во многих системах реализованы двусторонние каналы. В Unix SVR4 это обеспечивается самой функцией pipe, а во многих других ядрах — функцией socketpair. Но что в действительности представляет собой двусторонний канал? Представим себе сначала однонаправленный канал, изображенный на рис. 4.8.
Рис. 4.8. Односторонний канал