Внеполосные данные применяются не очень широко. Они используются в протоколах Telnet и Rlogin, а также FTP. Во всех случаях внеполосные данные уведомляют собеседника об исключительной ситуации (например, прерывании на стороне клиента), после чего собеседник сбрасывает все принятые данные до отметки внеполосных данных.
Упражнения
1. Есть ли разница между одним вызовом функции
send(fd, "ab", 2, MSG_OOB);
и двумя последовательными вызовами
send(fd, "a", 1, MSG_OOB);
send(fd, "b", 1, MSG_OOB);
?
2. Переделайте программу, приведенную в листинге 24.4, так, чтобы использовать функцию
poll
вместо функции
select
.
Глава 25
Управляемый сигналом ввод-вывод
25.1. Введение
Ввод-вывод, управляемый сигналом, подразумевает, что мы указываем ядру проинформировать нас сигналом, если что-либо произойдет с дескриптором. Исторически такой ввод-вывод назвали асинхронным вводом-выводом, но в действительности описанный далее управляемый сигналом ввод-вывод асинхронным не является. Последний обычно определяется как операция ввода-вывода с немедленным возвратом управления процессу после инициирования операции в ядре. Процесс продолжает выполняться во время того, как производится ввод-вывод. Когда операция ввода-вывода завершается или обнаруживается некоторая ошибка, процесс некоторым образом оповещается. В разделе 6.2 проводилось сравнение всех возможных типов ввода-вывода и было показано различие между вводом-выводом, управляемым сигналом, и асинхронным вводом-выводом.
Следует отметить, что неблокируемый ввод-вывод, описанный в главе 16, также не является асинхронным. При неблокируемом вводе-выводе ядро не возвращает управление после инициирования операции ввода-вывода. Управление возвращается немедленно, только если операция не может быть выполнена без блокирования процесса.
ПРИМЕЧАНИЕ
Стандарт POSIX обеспечивает истинный асинхронный ввод-вывод с помощью функций aio_XXX. Эти функции позволяют процессу решить, генерировать ли при завершении ввода-вывода сигнал, и какой именно.
Беркли-реализации поддерживают ввод-вывод, управляемый сигналом, для сокетов и устройств вывода с помощью сигнала
SIGIO
. SVR4 поддерживает ввод- вывод, управляемый сигналом, для устройств STREAMS с помощью сигнала
SIGPOLL
, который в данном случае приравнивается к
SIGIO
.
25.2. Управляемый сигналом ввод-вывод для сокетов
Для использования управляемого сигналом ввода-вывода с сокетом (
SIGIO
) необходимо, чтобы процесс выполнил три следующих действия:
1. Установил обработчик сигнала
SIGIO
.
2. Задал владельца сокета. Обычно это выполняется с помощью команды
F_SETOWN
функции
fcntl
(см. табл. 7.9).
3. Разрешил управляемый сигналом ввод-вывод для данного сокета, что обычно выполняется с помощью команды
F_SETFL
функции
fcntl
или путем включения флага
O_ASYNC
(см. табл. 7.9).
ПРИМЕЧАНИЕ
Флаг O_ASYNC был добавлен в POSIX относительно поздно. Его поддержка пока реализована в небольшом количестве систем. Для разрешения управляемого сигналом ввода-вывода в листинге 25.2 вместо этого флага мы используем функцию ioctl с флагом FIOASYNC. Следует отметить, что разработчики POSIX выбрали не самое удачное имя для нового флага: ему больше подходит имя O_SIGIO.
Обработчик сигнала должен быть установлен до того, как будет задан владелец сокета. В Беркли-реализациях порядок вызова этих функций не имеет значения, поскольку по умолчанию сигнал SIGIO игнорируется. Поэтому если изменить порядок вызова функций на противоположный, появится небольшая вероятность того, что сигнал будет сгенерирован после вызова функции fcntl, но перед вызовом функции signal. Однако если это произойдет, то сигнал просто не будет учитываться. В SVR4 SIGIO определяется в заголовочном файле <sys/signal.h> как SIGPOLL, а действием по умолчанию для SIGPOLL является прерывание процесса. Таким образом, в SVR4 желательно быть уверенным в том, что обработчик сигнала установлен до задания владельца сокета.
Перевести сокет в режим ввода-вывода, управляемого сигналом, несложно. Сложнее определить условия, которые должны приводить к генерации сигнала
SIGIO
для владельца сокета. Это зависит от транспортного протокола.
Сигнал SIGIO и сокеты UDP
Использовать ввод-вывод, управляемый сигналом, с сокетами UDP довольно легко. Сигнал генерируется в следующих случаях:
■ на сокет прибывает дейтаграмма;
■ на сокете возникает асинхронная ошибка.
Таким образом, когда мы перехватываем сигнал
SIGIO
для сокета UDP, вызывается функция
recvfrom
как для чтения дейтаграммы, так и для получения асинхронной ошибки. Асинхронные ошибки, касающиеся UDP-сокетов, обсуждались в разделе 8.9. Напомним, что эти сигналы генерируются, только если сокет UDP является присоединенным (создан с помощью вызова функции
connect
).
ПРИМЕЧАНИЕ
Сигнал SIGIO генерируется для этих двух условий путем вызова макроса sorwakeup, описываемого в книге [128, с. 775, с. 779, с. 784].
Сигнал SIGIO и сокеты TCP
К сожалению, использовать управляемый сигналом ввод-вывод для сокетов TCP почти бесполезно. Проблема состоит в том, что сигнал генерируется слишком часто, а само по себе возникновение сигнала не позволяет выяснить, что произошло. Как отмечается в [128, с. 439], генерацию сигнала
SIGIO
для TCP-сокета вызывают все нижеперечисленные ситуации (при условии, что управляемый сигналом ввод-вывод разрешен):
■ на прослушиваемом сокете выполнен запрос на соединение;
■ инициирован запрос на отключение;
■ запрос на отключение выполнен;
■ половина соединения закрыта;
■ данные доставлены на сокет;
■ данные отправлены с сокета (то есть в буфере отправки имеется свободное место);
■ произошла асинхронная ошибка.
Например, если одновременно осуществляются и чтение, и запись в TCP-сокет, то сигнал
SIGIO
генерируется, когда поступают новые данные и когда подтверждается прием ранее записанных данных, а обработчик сигнала не имеет возможности различить эти сигналы. Если используется сигнал
SIGIO
, то для предотвращения блокирования при выполнении функции
read
или
write
TCP-сокет должен находиться в режиме неблокируемого ввода-вывода. Следует использовать сигнал
SIGIO
лишь с прослушиваемым сокетом TCP, поскольку для прослушиваемого сокета этот сигнал генерируется только при завершении установления нового соединения.
Единственное реальное применение управляемого сигналом ввода-вывода с сокетами, которое удалось обнаружить автору, — это сервер NTP (Network Time Protocol — сетевой протокол синхронизации времени), использующий протокол UDP. Основной цикл этого сервера получает дейтаграмму от клиента и посылает ответ. Но обработка клиентского запроса на этом сервере требует некоторого ненулевого количества времени (больше, чем для нашего тривиального эхо-сервеpa). Серверу важно записать точные отметки времени для каждой принимаемой дейтаграммы, поскольку это значение возвращается клиенту и используется им для вычисления времени обращения к серверу (RTT). На рис. 25.1 показаны два варианта построения такого UDP-сервера.