Книга: 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
Наша программа относительно проста, потому что мы знаем, что дескрипторов всего два. В большой программе цикл будет более сложным. Возможно даже разделение программы на потоки для обработки данных, полученных по разным дескрипторам.
- 12. Лекция: Создание приложений с графическим интерфейсом пользователя.
- 5.21 IP-адреса, интерфейсы и множественное пребывание
- Множественные интерфейсы и имена методов
- 2.1 Интерфейс SCSI
- 2.2 Интерфейсы IDE, EIDE и АТА
- 7.2 Интерфейс WMI
- 7.5 Программные интерфейсы приложений для адаптеров шины
- Не допускайте того, чтобы поток пользовательского интерфейса блокировался на длительное время
- Абстрактные базы как двоичные интерфейсы
- Интерфейсы накопителей на жестких магнитных дисках
- Интерфейс SATA
- 8.4. Оформляем интерфейс проигрывателя