Книга: UNIX: разработка сетевых приложений
6.10. Функция poll
Разделы на этой странице:
6.10. Функция poll
Функция poll
появилась впервые в SVR3, и изначально ее применение ограничивалось потоковыми устройствами (STREAMS devices) (см. главу 31). В SVR4 это ограничение было снято, что позволило функции poll
работать с любыми дескрипторами. Функция poll
предоставляет функциональность, аналогичную функции select
, но позволяет получать дополнительную информацию при работе с потоковыми устройствами.
#include <poll.h>
int poll(struct pollfd *fdarray, unsigned long nfds, int timeout);
Возвращает: количество готовых дескрипторов, 0 в случае тайм-аута, -1 в случае ошибки
Первый аргумент — это указатель на первый элемент массива структур. Каждый элемент массива — это структура pollfd
, задающая условия, проверяемые для данного дескриптора fd
.
struct pollfd {
int fd; /* дескриптор, который нужно проверить */
short events; /* события на дескрипторе, которые нас интересуют */
short revents; /* события, произошедшие на дескрипторе fd */
};
Проверяемые условия задаются элементом events
, и состояние этого дескриптора функция возвращает в соответствующем элементе revents
. (Наличие двух переменных для каждого дескриптора, одна из которых — значение, а вторая — результат, дает возможность обойтись без аргументов типа «значение-результат». Вспомните, что три средних аргумента функции select
имеют тип «значение-результат».) Каждый из двух элементов состоит из одного или более битов, задающих определенное условие. В табл. 6.2 перечислены константы, используемые для задания флага events
и для проверки флага revents
.
Таблица 6.2. Различные значения флагов events и revents для функции poll
Константа | На входе (events) | На выходе (revents) | Описание |
---|---|---|---|
POLLIN | • | • | Можно считывать обычные или приоритетные данные |
POLLRDNORM | • | • | Можно считывать обычные данные |
POLLRDBAND | • | • | Можно считывать приоритетные данные |
POLLPRI | • | • | Можно считывать данные с высоким приоритетом |
POLLOUT | • | • | Можно записывать обычные данные |
POLLWRNORM | • | • | Можно записывать обычные данные |
POLLWRBAND | • | • | Можно записывать приоритетные данные |
POLLERR | • | Произошла ошибка | |
POLLHUP | • | Произошел разрыв соединения | |
POLLNVAL | • | Дескриптор не соответствует открытому файлу |
Мы разделили эту таблицу на три части: первые четыре константы относятся ко вводу, следующие три — к выводу, а последние три — к ошибкам. Обратите внимание, что последние три константы не могут устанавливаться в элементе events, но всегда возвращаются в revents, когда выполняется соответствующее условие.
Существует три класса данных, различаемых функцией poll
: обычные, приоритетные и данные с высоким приоритетом. Эти термины берут начало в реализациях, основанных на потоках (см. рис. 31.5).
ПРИМЕЧАНИЕ
Константа POLLIN может быть задана путем логического сложения констант POLLRDNORM и POLLRDBAND. Константа POLLIN существовала еще в реализациях SVR3, которые предшествовали полосам приоритета в SVR4, то есть эта константа существует в целях обратной совместимости. Аналогично, константа POLLOUT эквивалентна POLLWRNORM, и первая из них предшествовала второй.
Для сокетов TCP и UDP при описанных условиях функция poll
возвращает указанный флаг revent
. К сожалению, в определении функции poll
стандарта POSIX имеется множество слабых мест (неоднозначностей):
? Все регулярные данные TCP и все данные UDP считаются обычными.
? Внеполосные данные TCP (см. главу 24) считаются приоритетными.
? Когда считывающая половина соединения TCP закрывается (например, если получен сегмент FIN), это также считается равнозначным обычным данным, и последующая операция чтения возвратит нуль.
? Наличие ошибки для соединения TCP может расцениваться либо как обычные данные, либо как ошибка (POLLERR
). В любом случае последующая функция read возвращает -1, что сопровождается установкой переменной errno
в соответствующее значение. Это происходит при получении RST или истечении таймера.
? Информация о доступности нового соединения на прослушиваемом сокете может считаться либо обычными, либо приоритетными данными. В большинстве реализаций эта информация рассматривается как обычные данные.
Число элементов в массиве структур задается аргументом nfds
.
ПРИМЕЧАНИЕ
Исторически этот аргумент имел тип long без знака, что является некоторым излишеством. Достаточно будет типа int без знака. В Unix 98 для этого аргумента определяется новый тип — nfds_t.
Аргумент timeout
определяет, как долго функция находится в ожидании перед завершением. Положительным значением задается количество миллисекунд — время ожидания. В табл. 6.3 показаны возможные значения аргумента timeout
.
Таблица 6.3. Значения аргумента timeout для функции poll
Значение аргумента timeout | Описание |
---|---|
INFTIM | Ждать вечно |
0 | Возвращать управление немедленно, без блокирования |
>0 | Ждать в течение указанного числа миллисекунд |
Константа INFTIM
определена как отрицательное значение. Если таймер в данной системе не обеспечивает точность порядка миллисекунд, значение округляется в большую сторону до ближайшего поддерживаемого значения.
ПРИМЕЧАНИЕ
POSIX требует, чтобы константа INFTIM была определена в заголовочном файле <poll.h>, но многие системы все еще определяют ее в заголовочном файле <sys/stropts.h>.
Как и в случае функции select, любой тайм-аут, установленный для функции poll, ограничивается снизу разрешающей способностью часов в конкретной реализации (обычно 10 мс).
Функция poll
возвращает -1, если произошла ошибка, 0 — если нет готовых дескрипторов до истечения времени таймера, иначе возвращается число дескрипторов с ненулевым элементом revents
.
Если нас больше не интересует конкретный дескриптор, достаточно установить элемент fd
структуры pollfd
равным отрицательному значению. В этом случае элемент events
будет проигнорирован, а элемент revents
при возвращении функции будет сброшен в нуль.
Вспомните наши рассуждения в конце раздела 6.3 относительно константы FD_SETSIZE
и максимального числа дескрипторов в наборе в сравнении с максимальным числом дескрипторов для процесса. У нас не возникает подобных проблем с функцией poll
, поскольку вызывающий процесс отвечает за размещение массива структур pollfd
в памяти и за последующее сообщение ядру числа элементов в массиве. Не существует типа данных фиксированного размера, аналогичного fd_set
, о котором знает ядро.
ПРИМЕЧАНИЕ
POSIX требует наличия и функции select, и функции poll. Но если сравнивать их с точки зрения переносимости, то функцию select в настоящее время поддерживает больше систем, чем функцию poll. POSIX определяет также функцию pselect — усовершенствованную версию функции select, которая обеспечивает возможность блокирования сигналов и предоставляет лучшую разрешающую способность по времени, а для функции poll ничего подобного в POSIX нет.
- 6.9. Использование select и poll с очередями сообщений
- Глава 6 Мультиплексирование ввода-вывода: функции select и poll
- 2.1.3. Функция getopt_long()
- Группировка по встроенным функциям и UDF
- 19.1.1. Функция jQuery()
- Функция strcmp( )
- Управление функциями узла
- Функция программного обеспечения
- 3.2. Ключи типа key_t и функция ftok
- 9.10. Функция sctp_recvmsg
- Функция document
- Функция generate-id