Книга: UNIX: разработка сетевых приложений

Интерфейс /dev/poll

Интерфейс /dev/poll

В Solaris имеется специальный файл /dev/poll, с помощью которого можно опрашивать большее количество дескрипторов файлов. Проблема select и poll состоит в том, что список дескрипторов приходится передавать при каждом вызове. Устройство опроса поддерживает информацию о состоянии между вызовами, так что программа может подготовить список подлежащих опросу дескрипторов, а потом спокойно зациклиться в опросе и не заполнять список каждый раз.

После открытия /dev/poll программа должна инициализировать массив структур pollfd (тех же, которые используются функцией poll, но в этом случае поле revents не используется). Затем массив передается ядру вызовом write (структура записывается непосредственно в /dev/poll). После этого программа может вызывать ioctl DP_POLL и ждать событий. При вызове ioctl передается следующая структура:

struct dvpoll {
 struct pollfd* dp_fds;
 int            dp_nfds;
 int            dp_timeout;
};

Поле dp_fds указывает на буфер, используемый для хранения массива структур pollfd, возвращаемых вызовом ioctl. Поле dp_nfds задает размер буфера. Вызов ioctl блокируется до появления интересующих программу событий на любом из опрашиваемых дескрипторов, или до прохождения dp_timeout миллисекунд. При нулевом значении тайм-аута функция ioctl возвращается немедленно (то есть данный способ может использоваться для реализации неблокируемых сокетов). Тайм-аут, равный -1, означает неопределенно долгое ожидание.

Измененный код функции str_cli, переписанной из листинга 6.2 с использованием /dev/poll, приведен в листинге 14.7.

Листинг 14.7. Функция str_cli, использующая /dev/poll

//advio/str_cli_poll03.c
 1 #include "unp.h"
 2 #include <sys/devpoll.h>
 3 void
 4 str_cli(FILE *fp, int sockfd)
 5 {
 6  int stdineof;
 7  char buf[MAXLINE];
 8  int n;
 9  int wfd;
10  struct pollfd pollfd[2];
11  struct dvpoll dopoll;
12  int i;
13  int result;
14  wfd = Open("/dev/poll", O_RDWR, 0);
15  pollfd[0].fd = fileno(fp);
16  pollfd[0].events = POLLIN;
17  pollfd[0].revents = 0;
18  pollfd[1].fd = sockfd;
19  pollfd[1].events = POLLIN;
20  pollfd[1].revents = 0;
21  Write(wfd, pollfd, sizeof(struct pollfd) * 2);
22  stdineof = 0;
23  for (;;) {
24   /* блокирование до готовности сокета */
25   dopoll.dp_timeout = -1;
26   dopoll.dp_nfds = 2;
27   dopoll.dp_fds = pollfd;
28   result = Ioctl(wfd, DP_POLL, &dopoll);
29   /* цикл по готовым дескрипторам */
30   for (i = 0; i < result; i++) {
31    if (dopoll.dp_fds[i].fd == sockfd) {
32     /* сокет готов к чтению */
33     if ((n = Read(sockfd, buf, MAXLINE)) == 0) {
34      if (stdineof == 1)
35       return; /* нормальное завершение */
36      else
37       err_quit("str_cli: server terminated prematurely");
38     }
39     Write(fileno(stdout), buf, n);
40    } else {
41     /* дескриптор готов к чтению */
42     if ((n = Read(fileno(fp), buf, MAXLINE)) == 0) {
43      stdineof = 1;
44      Shutdown(sockfd, SHUT_WR); /* отправка FIN */
45      continue;
46     }
47     Writen(sockfd, buf, n);
48    }
49   }
50  }
51 }

Составление списка дескрипторов для /dev/poll

14-21 Заполнив массив структур pollfd, мы передаем его в /dev/poll. В нашем примере используются только два файловых дескриптора, так что мы помещаем их в статический массив. На практике программы, использующие /dev/poll, обычно следят за сотнями или даже тысячами дескрипторов одновременно, поэтому массив выделяется динамически.

Ожидание данных

24-28 Программа не вызывает select, а блокируется в вызове ioctl в ожидании поступления данных. Возвращаемое значение представляет собой количество готовых к чтению дескрипторов файлов.

Цикл по дескрипторам

30-49 Наша программа относительно проста, потому что мы знаем, что дескрипторов всего два. В большой программе цикл будет более сложным. Возможно даже разделение программы на потоки для обработки данных, полученных по разным дескрипторам.

Оглавление книги


Генерация: 0.152. Запросов К БД/Cache: 2 / 0
поделиться
Вверх Вниз