UNIX: разработка сетевых приложений
ПРИМЕЧАНИЕИсторически этот аргумент имел тип long без знака, что является некоторым излишеством. Достаточно будет типа int без знака. В Unix 98 для этого аргумента определяется новый тип — nfds_t.
Аргумент
определяет, как долго функция находится в ожидании перед завершением. Положительным значением задается количество миллисекунд — время ожидания. В табл. 6.3 показаны возможные значения аргументаtimeout.timeoutТаблица 6.3. Значения аргумента timeout для функции poll
Значение аргумента timeout Описание INFTIM Ждать вечно 0 Возвращать управление немедленно, без блокирования >0 Ждать в течение указанного числа миллисекунд Константа
определена как отрицательное значение. Если таймер в данной системе не обеспечивает точность порядка миллисекунд, значение округляется в большую сторону до ближайшего поддерживаемого значения.INFTIMПРИМЕЧАНИЕPOSIX требует, чтобы константа INFTIM была определена в заголовочном файле <poll.h>, но многие системы все еще определяют ее в заголовочном файле <sys/stropts.h>.
Как и в случае функции select, любой тайм-аут, установленный для функции poll, ограничивается снизу разрешающей способностью часов в конкретной реализации (обычно 10 мс).
Функция
возвращает -1, если произошла ошибка, 0 — если нет готовых дескрипторов до истечения времени таймера, иначе возвращается число дескрипторов с ненулевым элементомpoll.reventsЕсли нас больше не интересует конкретный дескриптор, достаточно установить элемент
структурыfdравным отрицательному значению. В этом случае элементpollfdбудет проигнорирован, а элементeventsпри возвращении функции будет сброшен в нуль.reventsВспомните наши рассуждения в конце раздела 6.3 относительно константы
и максимального числа дескрипторов в наборе в сравнении с максимальным числом дескрипторов для процесса. У нас не возникает подобных проблем с функциейFD_SETSIZE, поскольку вызывающий процесс отвечает за размещение массива структурpollв памяти и за последующее сообщение ядру числа элементов в массиве. Не существует типа данных фиксированного размера, аналогичногоpollfd, о котором знает ядро.fd_setПРИМЕЧАНИЕPOSIX требует наличия и функции select, и функции poll. Но если сравнивать их с точки зрения переносимости, то функцию select в настоящее время поддерживает больше систем, чем функцию poll. POSIX определяет также функцию pselect — усовершенствованную версию функции select, которая обеспечивает возможность блокирования сигналов и предоставляет лучшую разрешающую способность по времени, а для функции poll ничего подобного в POSIX нет.
6.11. Эхо-сервер TCP (еще раз)
Теперь мы изменим наш эхо-сервер TCP из раздела 6.8, используя вместо функции
функциюselect. В предыдущей версии сервера, работая с функциейpoll, мы должны были выделять массивselectвместе с набором дескрипторовclient(см. рис. 6.12). С помощью функцииrsetмы разместим в памяти массив структурpoll. В нем же мы будем хранить и информацию о клиенте, не создавая для нее другой массив. Элементpollfdэтого массива мы обрабатываем тем же способом, которым обрабатывали массивfd(см. рис. 6.12): значение -1 говорит о том, что элемент не используется, а любое другое значение является номером дескриптора. Вспомните из предыдущего раздела, что любой элемент в массиве структурclient, передаваемый функцииpollfdс отрицательным значением элементаpoll, просто игнорируется.fdВ листинге 6.5 показана первая часть кода нашего сервера.
Листинг 6.5. Первая часть сервера TCP, использующего функцию poll
//tcpcliserv/tcpservpoll01.с1 #include "unp.h"2 #include <1imits.h> /* для OPEN_MAX */3 int4 main(int argc, char **argv)5 {6 int i, maxi, listenfd, connfd, sockfd;7 int nready;8 ssize_t n;9 char buf[MAXLINE];10 socklen_t clilen;11 struct pollfd client[OPEN_MAX];12 struct sockaddr_in cliaddr, servaddr;13 listenfd = Socket(AF_INET, SOCK_STREAM, 0);14 bzero(&servaddr, sizeof(servaddr));15 servaddr.sin_family = AF_INET;16 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);17 servaddr.sin_port = htons(SERV_PORT);18 Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));19 Listen(listenfd, LISTENQ);20 client[0].fd = listenfd;21 client[0].events = POLLRDNORM;22 for (i = 1; i < OPEN_MAX; i++)23 client[i].fd = -1; /* -1 означает, что элемент свободен */24 maxi = 0; /* максимальный индекс массива client[] */Размещение массива структур pollfd в памятиМы объявляем массив структур11размеромpollfd. Не существует простого способа определить максимальное число дескрипторов, которые могут быть открыты процессом. Мы снова столкнемся с этой проблемой в листинге 13.1. Один из способов ее решения — вызвать функцию POSIXOPEN_MAXс аргументомsysconf[110, с. 42-44], а затем динамически выделять в памяти место для массива соответствующего размера. Однако функция_SC_OPEN_MAXможет возвратить некое «неопределенное» значение, и в этом случае нам придется задавать ограничение самим. Здесь мы используем только константуsysconfстандарта POSIX.OPEN_MAX