В принципе, события FD_XXX
Как и в случае с WSAAsyncSelect
WSAEventSelect
сокет переводится в неблокирующий режим. Повторный вызов WSAEventSelect
для данного сокета отменяет результаты предыдущего вызова (т.е. невозможно связать разные события FD_XXX
одного сокета с разными сокетными событиями). Сокет, созданный в результате вызова accept или WSAAccept
наследует связь с сокетными событиями, установленную для слушающего сокета.Существует весьма важное различие между использованием оконных сообщений и сокетных событий для оповещения о том, что происходит на сокете.
Предположим, с помощью функции WSAAsyncSelect
FD_READ
, FD_WRITE
и FD_CONNECT
связаны с некоторым оконным сообщением. Пусть происходит событие FD_CONNECT
. В очередь окна помещается соответствующее сообщение. Затем, до того, как предыдущее сообщение будет обработано, происходит FD_WRITE
. В очередь окна помещается еще одно сообщение, которое информирует об этом. И наконец, при возникновении FD_READ
в очередь будет помещено третье сообщение. Затем оконная процедура получит их по очереди и обработает.Теперь рассмотрим ситуацию, когда те же события связаны с сокетным событием. Когда происходит FD_CONNECT
FD_WRITE
и FD_READ
произойдут до того, как сокетное событие будет сброшено, оно уже не изменит своего состояния. Таким образом, программа, работающая с асинхронными сокетами, основанными на событиях, должна, во-первых, учитывать, что взведенное событие может означать несколько событий FD_XXX
, а во-вторых, иметь возможность узнать, какие именно события произошли с момента последней проверки. Для получения этой информации предусмотрена функция WSAEnumNetworkEvents
, прототип которой приведен в листинге 2.60.WSAEnumNetworkEvents
// ***** Описание на C++ *****
int WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEventObject, LPWSANETWORKEVENTS lpNetworkEvents);
// ***** Описание на Delphi *****
function WSAEnumNetworkEvents(S: TSocket; hEventObject: TWSAEvent; var NetworkEvents: TWSANetworkEvents): Integer;
Функция WSAEnumNetworkEvents
NetworkEvents
возвращает информацию о том, какие события произошли на сокете S с момента последнего вызова этой функции для данного сокета (или с момента запуска программы, если функция вызывается в первый раз). Параметр hEventObject
необязательный, он определяет сокетное событие, которое нужно сбросить. Использование этого параметра позволяет обойтись без явного вызова функции WSAResetEvent
для сброса события. Как и большинство функций WinSock, функция WSAEnumNetworkEvents
возвращает ноль в случае успеха и ненулевое значение при возникновении ошибки.Запись TWSANetworkEvents
TWSANetworkEvents
// ***** Описание на C++ *****
typedef struct _WSANETWORKEVENTS {
long lNetworkEvents;
int iErrorCode[FD_MAX_EVENTS];
} WSANETWORKEVENTS, *LPWSANETWORKEVENTS;
// ***** Описание на Delphi *****
TWSANetworkEvents = packed record
lNetworkEvents: LongInt;
iErrorCode: array[0..FD_MAX_EVENTS - 1] of Integer;
end;
Константа FD_MAX_EVENTS
Значения констант FD_XXX
lNetworkEvents
является таким объединением всех констант, задающих события, которые происходили на сокете. Другими словами, если результат операции (lNetworkEvents and FD_XXX
) не равен нулю, значит, событие FD_XXX
происходило на сокете.