Описанная схема, в принципе, достаточно удобна, но следует учитывать, что в некоторых случаях она может давать ложные срабатывания, т.е. при обработке сообщения о событии FD_READ
recv
завершится с ошибкой WSAEWOULDBLOCK
, показывающей, что входной буфер сокета пуст. Если программа читает данные из буфера не только при обработке FD_READ
, может возникнуть следующая ситуация: в буфер сокета поступают данные. Сообщение о событии FD_READ
помещается в очередь. Программа в это время отрабатывает какое-то другое сообщение, при обработке которого также читаются данные. В результате все данные извлекаются из буфера, и он остается пустым. Когда очередь доходит до обработки FD_READ
, читать из буфера уже нечего.Другой вариант ложного срабатывания возможен, если программа при обработке FD_READ
recv
, за исключением последнего, приводит к тому, что в очередь ставится новое сообщение о событии FD_READ
. Чтобы избежать появления пустых сообщении в подобных случаях, MSDN рекомендует перед началом чтения отключить для данного сокета реакцию на поступление данных, вызвав для него WSAAsyncSelect
без FD_READ
, а перед последним вызовом recv — снова включить.И наконец, следует помнить, что сообщение о событии FD_READ
WSAAsyncSelect
сокет будет переведен в синхронный режим. Это может случиться в том случае, когда на момент вызова WSAAsyncSelect
в очереди еще остались необработанные сообщения о событиях на данном сокете. Впрочем, это касается не только FD_READ
, а вообще любого события.Событие FD_WRITE
При использовании TCP первый раз сообщение, уведомляющее о событии FD_WRITE
connect
, если речь идет о клиенте, или сразу после создания сокета функцией accept
или ее аналогом в случае сервера. В случае UDP это событие возникает после привязки сокета к адресу явным или неявным вызовом функции bind
. Если на момент вызова WSAAsyncSelect
описанные действия уже выполнены, событие FD_WRITE
также генерируется.В следующий раз событие может возникнуть только в том случае, если функция send
sendto
) не смогла положить данные в буфер из-за нехватки места в нем (в этом случае функция вернет значение, меньшее, чем размер переданных данных, или завершится с ошибкой WSAEWOULBBLOCK
). Как только в выходном буфере сокета снова появится свободное место, возникнет событие FD_WRITE
, показывающее, что программа может продолжить отправку данных. Если же программа отправляет данные не очень большими порциями и относительно редко, не переполняя буфер, то второй раз событие FD_WRITE
не возникнет никогда.Событие FD_ACCEPT
FD_READ
, за исключением того, что оно возникает не при получении данных, а при подключении клиента. После постановки сообщения о событии FD_ACCEPT
в очередь новые сообщения о FD_ACCEPT
для данного сокета в очередь не ставятся, пока не будет вызвана функция accept
или WSAAccept
. При вызове одной из этих функций сообщение о событии вновь помещается в очередь окна, если в очереди подключений после вызова функции остаются подключения.Событие FD_CONNECT
connect
, для серверных — после создания нового сокета с помощью функции accept
(событие возникает именно на новом сокете, а не на том, который находится в режиме ожидания подключения). В MSDN написано, что оно должно возникать также и после выполнения connect
для сокетов, не поддерживающих соединение, однако для UDP практика это не подтверждает. Событие FD_CONNECT
также возникает, если при попытке установить соединение произошла ошибка (например, оказался недоступен указанный сетевой адрес). Поэтому при получении этого события необходимо анализировать старшее слово параметра lParam
, чтобы понять, удалось ли установить соединение.