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

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

Листинг 4.7. Функция main независимого сервера

//pipe/server_main.c

1  #include "fifo.h"

2  void server(int, int);

3  int

4  main(int argc, char **argv)

5  {

6   int readfd, writefd;

7   /* создание двух FIFO. OK, если они существуют */

8   if ((mkfifo(FIF01, FILE_MODE) < 0) && (errno != EEXIST))

9    err_sys("can't create %s", FIF01);

10  if ((mkfifo(FIF02, FILE MODE) < 0) && (errno != EEXIST)) {

11   unlink(FIF01);

12   err_sys("can't create %s", FIF02);

13  }

14  readfd = Open(FIF01, O_RDONLY, 0);

15  writefd = Open(FIFO2, O_WRONLY, 0);

16  server(readfd, writefd);

17  exit(0);

18 } 

Листинг 4.8. Заголовочный файл fifo.h, используемый и клиентом, и сервером

//pipe/fifo.h

1 #include "unpipc.h"

2 #define FIFO1 "/tmp/fifo.1"

3 #define FIFO2 "/tmp/fifo.2"

Листинг 4.9. Функция main независимого клиента

//pipe/client_main.c

1  #include "fifo.h"

2  void client(int, int);

3  int

4  main(int argc, char **argv)

5  {

6   int readfd, writefd;

7   writefd = Open(FIFO1, O_WRONLY, 0);

8   readfd = Open(FIFO2, O_RDONLY, 0);

9   client(readfd, writefd);

10  Close(readfd);

11  Close(writefd);

12  Unlink(FIFO1);

13  UnLink(FIFO2);

14  exit(0);

15 }

ПРИМЕЧАНИЕ

Для программных каналов и каналов FIFO ядро ведет подсчет числа открытых дескрипторов, относящихся к ним, поэтому безразлично, кто именно вызовет unlink — клиент или сервер. Хотя эта функция и удаляет файл из файловой системы, она не влияет на открытые в момент ее выполнения дескрипторы. Однако для других форм IPC, таких как очереди сообщений стандарта System V, счетчик отсутствует, и если сервер удалит очередь после записи в нее последнего сообщения, она может быть удалена еще до того, как клиент это сообщение считает.

Для запуска клиента и сервера запустите сервер в фоновом режиме:

% server_fifo &

а затем запустите клиент. Можно было сделать и по-другому: запускать только программу-клиент, которая запускала бы сервер с помощью fork и exec. Клиент мог бы передавать серверу имена FIFO в качестве аргументов командной строки в команде exec, вместо того чтобы обе программы считывали их из заголовка. Но в этом случае сервер являлся бы дочерним процессом и проще было бы обойтись программным каналом.

4.7. Некоторые свойства именованных и неименованных каналов

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

1. При вызове open указать флаг O_NONBLOCK. Например, первый вызов open в листинге 4.9 мог бы выглядеть так:

writefd = Open(FIFO1, O_WRONLY | O_NONBLOCK, 0);

2. Если дескриптор уже открыт, можно использовать fcntl для включения флага O_NONBLOCK. Этот прием нужно применять для программных каналов, поскольку для них не вызывается функция open и нет возможности указать флаг O_NONBLOCK при ее вызове. Используя fcntl, мы сначала получаем текущий статус файла с помощью F_GETFL, затем добавляем к нему с помощью побитового логического сложения (OR) флаг O_NONBLOCK и записываем новый статус с помощью команды F_SETFL: