Флаг O_ASYNC был добавлен в POSIX относительно поздно. Его поддержка пока реализована в небольшом количестве систем. Для разрешения управляемого сигналом ввода-вывода в листинге 25.2 вместо этого флага мы используем функцию ioctl с флагом FIOASYNC. Следует отметить, что разработчики POSIX выбрали не самое удачное имя для нового флага: ему больше подходит имя O_SIGIO.
Обработчик сигнала должен быть установлен до того, как будет задан владелец сокета. В Беркли-реализациях порядок вызова этих функций не имеет значения, поскольку по умолчанию сигнал SIGIO игнорируется. Поэтому если изменить порядок вызова функций на противоположный, появится небольшая вероятность того, что сигнал будет сгенерирован после вызова функции fcntl, но перед вызовом функции signal. Однако если это произойдет, то сигнал просто не будет учитываться. В SVR4 SIGIO определяется в заголовочном файле
Перевести сокет в режим ввода-вывода, управляемого сигналом, несложно. Сложнее определить условия, которые должны приводить к генерации сигнала 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, поскольку для прослушиваемого сокета этот сигнал генерируется только при завершении установления нового соединения.