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

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

Пример

В листинге 4.5 изображено еще одно решение задачи с клиентом и сервером, использующее функцию popen и программу (утилиту Unix) cat.

Листинг 4.5. Клиент-сервер с использованием popen

//pipe/mainpopen.c

1  #include "unpipc.h"

2  int

3  main(int argc, char **argv)

4  {

5   size_t n;

6   char buff[MAXLINE], command[MAXLINE];

7   FILE *fp;

8   /* считывание полного имени */

9   Fgets(buff, MAXLINE, stdin);

10  n = strlen(buff); /* fgets() гарантирует завершающий ноль */

11  if (buff[n-1] == '\n')

12   n--; /* удаление перевода строки из возврата fgets() */

13  snprintf(command, sizeof(command), "cat %s", buff);

14  fp = Popen(command, "r");

15  /* копирование из канала в стандартный вывод */

16  while(Fgets(buff, MAXLINE, fp) != NULL)

17   Fputs(buff, stdout);

18  Pclose(fp);

19  exit(0);

20 }

8-17 Полное имя файла считывается из стандартного потока ввода, как и в программе в листинге 4.2. Формируется командная строка, которая передается popen. Вывод интерпретатора команд или команды cat копируется в стандартный поток вывода.

Одним из отличий этой реализации от приведенной в листинге 4.1 является отсутствие возможности формировать собственные сообщения об ошибках. Теперь мы целиком зависим от программы cat, а выводимые ею сообщения не всегда адекватны. Например, в системе Solaris 2.6 при попытке считать данные из файла, доступ на чтение к которому для нас запрещен, будет выведена следующая ошибка:

solaris % cat/etc/shadow

cat: cannot open /etc/shadow 

А в BSD/OS 3.1 мы получим более информативное сообщение в аналогичной ситуации:

bsdi % cat /etc/master.passwd

cat: /etc/master.passwd: cannot open [Permission denied]

Обратите также внимание на тот факт, что вызов popen в данном случае оказывается успешным, однако при первом же вызове fgets будет возвращен символ конца файла (EOF). Программа cat записывает сообщение об ошибке в стандартный поток сообщений об ошибках (stderr), а popen с этим потоком не связывается — к создаваемому каналу подключается только стандартный поток вывода.

4.6. Именованные каналы (FIFO)

Программные каналы не имеют имен, и их главным недостатком является невозможность передачи информации между неродственными процессами. Два неродственных процесса не могут создать канал для связи между собой (если не передавать дескриптор).

Аббревиатура FIFO расшифровывается как «first in, first out» — «первым вошел, первым вышел», то есть эти каналы работают как очереди. Именованные каналы в Unix функционируют подобно неименованным — они позволяют передавать данные только в одну сторону. Однако в отличие от программных каналов каждому каналу FIFO сопоставляется полное имя в файловой системе, что позволяет двум неродственным процессам обратиться к одному и тому же FIFO.

FIFO создается функцией mkfifо:

#include <sys/types.h>

#include <sys/stat.h>

int mkfifo(const char *раthnаme, mode_t mоdе);

/* Возвращает 0 при успешном выполнении, –1 – при возникновении ошибок */

Здесь pathname — обычное для Unix полное имя файла, которое и будет именем FIFO.