UNIX: разработка сетевых приложений
Мы поговорим о функции
более подробно и приведем ее пример в разделе 20.5. Функциюpselectмы используем в листинге 20.3, а в листинге 20.4 показываем простую, хотя и не вполне корректную реализацию этой функции.pselectПРИМЕЧАНИЕЕсть одно незначительное различие между функциями select и pselect. Первый элемент структуры timeval является целым числом типа long со знаком, в то время как первый элемент структуры timspec имеет тип time_t. Число типа long со знаком в первой функции также должно было относиться к типу time_t, но мы не меняли его тип, чтобы не разрушать существующего кода. Однако в новой функции это можно было бы сделать.
6.10. Функция poll
Функция
появилась впервые в SVR3, и изначально ее применение ограничивалось потоковыми устройствами (STREAMS devices) (см. главу 31). В SVR4 это ограничение было снято, что позволило функцииpollработать с любыми дескрипторами. Функцияpollпредоставляет функциональность, аналогичную функцииpoll, но позволяет получать дополнительную информацию при работе с потоковыми устройствами.select#include <poll.h>int poll(struct pollfd *<i>fdarray</i>, unsigned long <i>nfds</i>, int <i>timeout</i>);<i>Возвращает: количество готовых дескрипторов, 0 в случае тайм-аута, -1 в случае ошибки</i>Первый аргумент — это указатель на первый элемент массива структур. Каждый элемент массива — это структура
, задающая условия, проверяемые для данного дескриптораpollfd.fdstruct pollfd {int fd; /* дескриптор, который нужно проверить */short events; /* события на дескрипторе, которые нас интересуют */short revents; /* события, произошедшие на дескрипторе fd */};Проверяемые условия задаются элементом
, и состояние этого дескриптора функция возвращает в соответствующем элементеevents. (Наличие двух переменных для каждого дескриптора, одна из которых — значение, а вторая — результат, дает возможность обойтись без аргументов типа «значение-результат». Вспомните, что три средних аргумента функцииreventsимеют тип «значение-результат».) Каждый из двух элементов состоит из одного или более битов, задающих определенное условие. В табл. 6.2 перечислены константы, используемые для задания флагаselectи для проверки флагаevents.reventsТаблица 6.2. Различные значения флагов events и revents для функции poll
Константа На входе (events) На выходе (revents) Описание POLLIN • • Можно считывать обычные или приоритетные данные POLLRDNORM • • Можно считывать обычные данные POLLRDBAND • • Можно считывать приоритетные данные POLLPRI • • Можно считывать данные с высоким приоритетом POLLOUT • • Можно записывать обычные данные POLLWRNORM • • Можно записывать обычные данные POLLWRBAND • • Можно записывать приоритетные данные POLLERR • Произошла ошибка POLLHUP • Произошел разрыв соединения POLLNVAL • Дескриптор не соответствует открытому файлу Мы разделили эту таблицу на три части: первые четыре константы относятся ко вводу, следующие три — к выводу, а последние три — к ошибкам. Обратите внимание, что последние три константы не могут устанавливаться в элементе events, но всегда возвращаются в revents, когда выполняется соответствующее условие.
Существует три класса данных, различаемых функцией
: обычные, приоритетные и данные с высоким приоритетом. Эти термины берут начало в реализациях, основанных на потоках (см. рис. 31.5).pollПРИМЕЧАНИЕКонстанта POLLIN может быть задана путем логического сложения констант POLLRDNORM и POLLRDBAND. Константа POLLIN существовала еще в реализациях SVR3, которые предшествовали полосам приоритета в SVR4, то есть эта константа существует в целях обратной совместимости. Аналогично, константа POLLOUT эквивалентна POLLWRNORM, и первая из них предшествовала второй.
Для сокетов TCP и UDP при описанных условиях функция
возвращает указанный флагpoll. К сожалению, в определении функцииreventстандарта POSIX имеется множество слабых мест (неоднозначностей):poll■ Все регулярные данные TCP и все данные UDP считаются обычными.
■ Внеполосные данные TCP (см. главу 24) считаются приоритетными.
■ Когда считывающая половина соединения TCP закрывается (например, если получен сегмент FIN), это также считается равнозначным обычным данным, и последующая операция чтения возвратит нуль.
■ Наличие ошибки для соединения TCP может расцениваться либо как обычные данные, либо как ошибка (
). В любом случае последующая функция read возвращает -1, что сопровождается установкой переменнойPOLLERRв соответствующее значение. Это происходит при получении RST или истечении таймера.errno■ Информация о доступности нового соединения на прослушиваемом сокете может считаться либо обычными, либо приоритетными данными. В большинстве реализаций эта информация рассматривается как обычные данные.
Число элементов в массиве структур задается аргументом
.nfds