Вход/Регистрация
UNIX: взаимодействие процессов
вернуться

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

Шрифт:

4.8. Один сервер, несколько клиентов

Преимущества канала FIFO проявляются более явно в том случае, когда сервер представляет собой некоторый длительно функционирующий процесс (например, демон, наподобие описанного в главе 12 [24]), не являющийся родственным клиенту. Демон создает именованный канал с вполне определенным известным именем, открывает его на чтение, а запускаемые впоследствии клиенты открывают его на запись и отправляют демону команды и необходимые данные. Односторонняя связь в этом направлении (от клиента к серверу) легко реализуется с помощью FIFO, однако необходимость отправки данных в обратную сторону (от сервера к клиенту) усложняет задачу. Рисунок 4.12 иллюстрирует прием, применяемый в этом случае. 

Рис. 4.12. Один сервер, несколько клиентов

Сервер создает канал с известным полным именем, в данном случае /tmp/fifо.serv. Из этого канала он считывает запросы клиентов. Каждый клиент при запуске создает свой собственный канал, полное имя которого определяется его идентификатором процесса. Клиент отправляет свой запрос в канал сервера с известным именем, причем запрос этот содержит идентификатор процесса клиента и имя файла, отправку которого клиент запрашивает у сервера. В листинге 4.10 приведен текст программы сервера.

Листинг 4.10. Сервер, обслуживающий несколько клиентов с помощью канала FIFO

//fifocliserv/mainserver.с

1 #include "fifo.h"

2 void server(int, int);

3 int

4 main(int argc, char **argv)

5 {

6 int readfifo, writefifo, dummyfd, fd;

7 char *ptr, buff[MAXLINE], fifoname[MAXLINE];

8 pid_t pid;

9 ssize_t n;

10 /* создание FIFO сервера с известным именем. ОК, если уже существует */

11 if ((mkfifo(SERV_FIFO, FILE_MODE) < 0) && (errno != EEXIST))

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

13 /* открытие FIFO-cepвepa на чтение */

14 readfifo = Open(SERV_FIFO, O_RDONLY, 0);

15 dummyfd = Open(SERV_FIFO, O_WRONLY, 0); /* не используется */

16 while ((n = Readline(readfifo, buff, MAXLINE)) > 0) {

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

18 n--; /* delete newline from readline */

19 buff[n] = '\0'; /* полное имя, завершаемое 0 */

20 if ((ptr = strchr(buff, ' ')) == NULL) {

21 err_msg("bogus request: ls", buff);

22 continue;

23 }

24 *ptr++ = 0; /* идентификатор процесса, указатель на имя файла */

25 pid = atol(buff);

26 snprintf(fifoname, sizeof(fifoname), "/tmp/fifo.%ld", (long) pid);

27 if ( (writefifo = open(fifoname, O_WRONLY, 0)) < 0) {

28 err_msg("cannot open: ls", fifoname);

29 continue;

30 }

31 if ((fd = open(ptr, O_RDONLY)) < 0) {

32 /* ошибка, нужно сообщить клиенту */

33 snprintf(buff + n, sizeof(buff) – n, ": can't open, %s\n",

34 strerror(errno));

35 n = strlen(ptr);

36 Write(writefifo, ptr, n);

37 Close(writefifo);

38

39 } else {

40 /* успешное открытие, копируем файл */

41 while ((n = Read(fd, buff, MAXLINE)) > 0)

42 Write(writefifo, buff, n);

43 Close(fd);

44 Close(writefifo);

45 }

46 }

47 }

Создание канала и открытие его только для записи и только для чтения

10-15 Сервер создает канал FIFO с известным именем, обрабатывая ситуацию, когда такой канал уже существует. Затем этот канал открывается дважды: один раз только для чтения, а второй — только для записи. Дескриптор readfifo используется для приема запросов от клиентов, а дескриптор dummyfd не используется вовсе. Причина, по которой нужно открыть канал для записи, видна из табл. 4.1. Если канал не открыть на запись, то при завершении работы очередного клиента этот канал будет опустошаться и сервер будет считывать 0, означающий конец файла. Пришлось бы каждый раз закрывать канал вызовом close, а затем заново открывать его с флагом O_RDONLY, что приводило бы к блокированию демона до подключения следующего клиента. Мы же всегда будем иметь дескриптор, открытый на запись, поэтому функция read не будет возвращать 0, означающий конец файла, при отсутствии клиентов. Вместо этого сервер просто будет блокироваться при вызове read, ожидая подключения следующего клиента. Этот трюк упрощает код программы-сервера и уменьшает количество вызовов open для канала сервера.

  • Читать дальше
  • 1
  • ...
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: