Функция WSAEventSelect (winsock2.h)

Функция WSAEventSelect указывает объект события, связанный с указанным набором FD_XXX сетевых событий.

Синтаксис

int WSAAPI WSAEventSelect(
  [in] SOCKET   s,
  [in] WSAEVENT hEventObject,
  [in] long     lNetworkEvents
);

Параметры

[in] s

Дескриптор, определяющий сокет.

[in] hEventObject

Дескриптор, определяющий объект события, связанный с указанным набором FD_XXX сетевых событий.

[in] lNetworkEvents

Битовая маска, указывающая сочетание FD_XXX сетевых событий, в которых заинтересовано приложение.

Возвращаемое значение

Возвращаемое значение равно нулю, если спецификация приложения сетевых событий и связанного объекта события была успешной. В противном случае возвращается значение SOCKET_ERROR, а определенный номер ошибки можно получить, вызвав WSAGetLastError.

Как и в случае с функциями select и WSAsyncSelect , WSAEventSelect часто используется для определения того, когда операция передачи данных (отправка или восстановление) может быть выполнена с ожиданием немедленного успеха. Тем не менее, надежное приложение должно быть готово к тому, что объект события задан и он выдает вызов Сокетов Windows, который немедленно возвращает WSAEWOULDBLOCK . Например, возможна следующая последовательность операций:

  • Данные поступают в сокеты; Сокеты Windows задает объект события WSAEventSelect .
  • Приложение выполняет некоторую другую обработку.
  • Во время обработки приложение выдает ioctlsocket(s, FIONREAD...) и замечает, что есть данные, готовые для чтения.
  • Приложение выдает recv(s,...) для чтения данных.
  • В конечном итоге приложение ожидает объект события, указанный в WSAEventSelect, который возвращает немедленно, указывая, что данные готовы к чтению.
  • Приложение выдает ошибку recv(s,...), которая завершается ошибкой WSAEWOULDBLOCK.
После успешной записи возникновения сетевого события (путем задания соответствующего бита во внутренней записи сетевого события) и передачи сигнала связанному объекту события дальнейшие действия для этого сетевого события не выполняются до тех пор, пока приложение не вызовет функцию, которая неявно повторно включает параметр этого сетевого события и сигнал связанного объекта события.
Сетевое событие Повторное включение функции
FD_READ
Функция recv, recvfrom, WSARecv, WSARecvEx или WSARecvFrom .
FD_WRITE
Функция send, sendto, WSASend или WSASendTo .
FD_OOB
Функция recv, recvfrom, WSARecv, WSARecvEx или WSARecvFrom .
FD_ACCEPT
Функция accept, AcceptEx или WSAAccept , если возвращенный код ошибки не WSATRY_AGAIN, указывающий, что функция условия вернула CF_DEFER.
FD_CONNECT
Нет.
FD_CLOSE
Нет.
FD_QOS
Функция WSAIoctl с командой SIO_GET_QOS.
FD_GROUP_QOS
Зарезервировано.
FD_ROUTING_ INTERFACE_CHANGE
Функция WSAIoctl с командой SIO_ROUTING_INTERFACE_CHANGE.
FD_ADDRESS_ LIST_CHANGE
Функция WSAIoctl с командой SIO_ADDRESS_LIST_CHANGE.
 

Любой вызов процедуры повторного преобразования, даже если он завершается сбоем, приводит к повторной записи и сигнализации для соответствующего сетевого события и объекта события.

Для FD_READ, FD_OOB и FD_ACCEPT сетевых событий запись сетевых событий и сигнализация объекта события активируются на уровне. Это означает, что если вызывается подпрограмма повторного преобразования и соответствующее условие сети остается действительным после вызова, сетевое событие записывается и задается связанный объект события. Это позволяет приложению управлять событиями и не беспокоиться о объеме данных, поступающих в любой момент времени. Рассмотрим следующую последовательность:

  1. Поставщик транспорта получает 100 байт данных в сокетах и заставляет WS2_32.DLL записывать сетевое событие FD_READ и задавать связанный объект события.
  2. Приложение выдает recv(s, buffptr, 50, 0) для чтения 50 байт.
  3. Поставщик транспорта заставляет WS2_32.DLL записывать сетевое событие FD_READ и снова задает связанный объект события, так как данные еще не считываются.
При использовании этой семантики приложению не требуется считывать все доступные данные в ответ на сетевое событие FD_READ . В ответ на каждое сетевое событие FD_READ подходит одна функция recv .

Событие FD_QOS считается запущенным ребром. Сообщение будет опубликовано ровно один раз при изменении качества обслуживания. Дальнейшие сообщения не будут получаться, пока поставщик не обнаружит дальнейшее изменение качества обслуживания или приложение не пересматривает качество обслуживания для сокета.

События FD_ROUTING_INTERFACE_CHANGE и FD_ADDRESS_LIST_CHANGE также считаются активированными по краям. Сообщение будет опубликовано ровно один раз, когда произойдет изменение после запроса уведомления приложением путем выдачи WSAIoctl с SIO_ROUTING_INTERFACE_CHANGE или SIO_ADDRESS_LIST_CHANGE соответственно. Другие сообщения не будут приходить, пока приложение повторно не выдаст IOCTL и не будет обнаружено другое изменение после выдачи IOCTL.

Если сетевое событие уже произошло, когда приложение вызывает WSAEventSelect или вызывается функция reenabling, то сетевое событие записывается и соответствующий объект события задается соответствующим образом. Например, рассмотрим следующую последовательность:

  1. Приложение вызывает прослушивание.
  2. Запрос на подключение получен, но еще не принят.
  3. Приложение вызывает WSAEventSelect , указывая, что оно заинтересовано в сетевом событии FD_ACCEPT для сокета. Из-за сохраняемости сетевых событий Сокеты Windows записывают сетевое событие FD_ACCEPT и немедленно задает связанный объект события.
Сетевое событие FD_WRITE обрабатывается немного иначе. Сетевое событие FD_WRITE записывается, когда сокет сначала подключается с помощью вызова функции connect, ConnectEx, WSAConnect, WSAConnectByList или WSAConnectByName или когда сокет принимается с функцией accept, AcceptEx или WSAAccept , а затем после сбоя отправки с WSAEWOULDBLOCK становится доступным буферное пространство. Таким образом, приложение может предположить, что отправка возможна, начиная с первого параметра сетевого события FD_WRITE и длиться до тех пор, пока отправка не вернет WSAEWOULDBLOCK. После такого сбоя приложение узнает, что отправки снова возможны при записи сетевого события FD_WRITE и установке связанного объекта события.

Сетевое событие FD_OOB используется только в том случае, если сокет настроен для получения данных OOB отдельно. Если сокет настроен для получения данных OOB в встроенном режиме, данные OOB (ускоряемые) обрабатываются как обычные данные, и приложение должно зарегистрировать интерес и получить FD_READ сетевое событие, а не сетевое событие FD_OOB. Приложение может задать или проверить способ обработки данных OOB с помощью метода setsockopt или getsockopt для параметра SO_OOBINLINE.

Код ошибки в сетевом событии FD_CLOSE указывает, было ли закрытие сокета корректно или прервано. Если код ошибки равен нулю, то закрытие было корректно; Если код ошибки — WSAECONNRESET, то виртуальный канал сокета был сброшен. Это относится только к сокетам, ориентированным на подключение, таким как SOCK_STREAM.

Сетевое событие FD_CLOSE записывается при получении указания закрытия для виртуального канала, соответствующего сокету. С точки зрения TCP это означает, что FD_CLOSE записывается, когда подключение переходит в состояния TIME WAIT или CLOSE WAIT. Это происходит из-за того, что удаленный конец выполняет завершение работы на стороне отправки или закрытие. FD_CLOSE публикации после считывания всех данных из сокета. Приложение должно проверка оставшихся данных после получения FD_CLOSE, чтобы избежать любой возможности потери данных. Дополнительные сведения см. в разделе Корректное завершение работы, параметры задержки и Закрытие сокета и функция завершения работы .

Обратите внимание, что сокеты Windows записывают только сетевое событие FD_CLOSE, указывающее на закрытие виртуального канала. Он не будет записывать сетевое событие FD_READ, чтобы указать это условие.

Сетевое событие FD_QOS или FD_GROUP_QOS записывается при любом параметре в спецификации потока, связанном с сокетами. Приложения должны использовать WSAIoctl с командой SIO_GET_QOS, чтобы получить текущее качество обслуживания для сокетов.

Сетевое событие FD_ROUTING_INTERFACE_CHANGE записывается, когда локальный интерфейс, который должен использоваться для достижения назначения, указанного в WSAIoctl , с SIO_ROUTING_INTERFACE_CHANGE изменениями после выдачи такого IOCTL.

Сетевое событие FD_ADDRESS_LIST_CHANGE записывается, когда список адресов семейства протоколов для сокета, к которому приложение может привязаться, изменяется после выдачи WSAIoctl с SIO_ADDRESS_LIST_CHANGE .

Код ошибки Значение
WSANOTINITIALISED Перед использованием этой функции должен быть выполнен успешный вызов WSAStartup .
WSAENETDOWN Произошел сбой сетевой подсистемы.
WSAEINVAL Один из указанных параметров является недопустимым, или указанный сокет находится в недопустимом состоянии.
WSAEINPROGRESS Выполняется блокирующий вызов Windows Sockets 1.1 или поставщик услуг по-прежнему обрабатывает функцию обратного вызова.
WSAENOTSOCK Дескриптор не является сокетом.

Комментарии

Функция WSAEventSelect используется для указания объекта события hEventObject, связанного с выбранным FD_XXX сетевыми событиями lNetworkEvents. Сокет, для которого указан объект события, определяется параметром s . Объект события задается при возникновении любого из назначенных сетевых событий.

Функция WSAEventSelect работает аналогично WSAAsyncSelect. Разница заключается в действиях, выполняемых при возникновении назначенного сетевого события. Функция WSAsyncSelect приводит к публикации сообщения Windows, указанного приложением. WSAEventSelect задает связанный объект события и записывает вхождение этого события во внутреннюю запись сетевого события. Приложение может использовать WSAWaitForMultipleEvents для ожидания или опроса объекта события, а также использовать WSAEnumNetworkEvents для получения содержимого записи внутреннего сетевого события и таким образом определить, какие из назначенных сетевых событий произошли.

Правильный способ сбросить состояние объекта события, используемого с функцией WSAEventSelect , — передать дескриптор объекта события в функцию WSAEnumNetworkEventS впараметре hEventObject . Это приведет к сбросу объекта события и настройке состояния активных событий FD в сокете атомарным образом.

WSAEventSelect — это единственная функция, которая вызывает запись и извлечение сетевых действий и ошибок через WSAEnumNetworkEvents. Ознакомьтесь с описаниями select и WSAAsyncSelect , чтобы узнать, как эти функции сообщают о сетевой активности и ошибках.

Функция WSAEventSelect автоматически устанавливает сокеты в неблокируемый режим независимо от значения lNetworkEvents. Чтобы вернуть сокеты в режим блокировки, сначала необходимо очистить запись события, связанную с сокетами , с помощью вызова WSAEventSelect с параметром lNetworkEvents , равным нулю, а для параметра hEventObjectзначение NULL. Затем можно вызвать ioctlsocket или WSAIoctl , чтобы вернуть сокет в режим блокировки.

Параметр lNetworkEvents создается с помощью побитового оператора OR с любым из значений, указанных в следующем списке.

Значение Значение
FD_READ Хочет получать уведомление о готовности к чтению.
FD_WRITE Хочет получать уведомление о готовности к написанию.
FD_OOB Хочет получать уведомление о поступлении данных OOB.
FD_ACCEPT Хочет получать уведомления о входящих подключениях.
FD_CONNECT Хочет получать уведомление о завершении подключения или операции многоточечего соединения.
FD_CLOSE Хочет получать уведомление о закрытии сокета.
FD_QOS Хочет получать уведомление об изменениях сокета (QoS.
FD_GROUP_QOS Зарезервировано для дальнейшего использования с группами сокетов. Хотите получать уведомление об изменениях качества обслуживания группы сокетов.
FD_ROUTING_ INTERFACE_CHANGE Хочет получать уведомления об изменениях интерфейса маршрутизации для указанного назначения.
FD_ADDRESS_ LIST_CHANGE Хочет получать уведомление об изменениях локального списка адресов для семейства адресов сокета.
 

Выдача WSAEventSelect для сокета отменяет все предыдущие WSAAsyncSelect или WSAEventSelect для того же сокета и очищает запись внутреннего сетевого события. Например, чтобы связать объект события с чтением и записью сетевых событий, приложение должно вызвать WSAEventSelect с FD_READ и FD_WRITE следующим образом:

rc = WSAEventSelect(s, hEventObject, FD_READ|FD_WRITE);

Невозможно указать разные объекты событий для разных сетевых событий. Приведенный ниже код не будет работать. второй вызов отменит эффекты первого, и только сетевое событие FD_WRITE будет связано с hEventObject2:

rc = WSAEventSelect(s, hEventObject1, FD_READ);
rc = WSAEventSelect(s, hEventObject2, FD_WRITE); //bad

Чтобы отменить связь и выбор сетевых событий в сокете, для параметра lNetworkEvents должно быть задано значение 0. В этом случае параметр hEventObject будет игнорироваться.

rc = WSAEventSelect(s, hEventObject, 0);

Закрытие сокета с помощью closesocket также отменяет связь и выбор сетевых событий, указанных в WSAEventSelect для сокета. Однако приложение по-прежнему должно вызывать WSACloseEvent , чтобы явным образом закрыть объект события и освободить все ресурсы.

Сокет, созданный при вызове функции accept , имеет те же свойства, что и сокет прослушивания, используемый для ее принятия. Любой набор выбора связей WSAEventSelect и сетевых событий для прослушивающего сокета применяется к принятому сокету. Например, если прослушивающий сокет имеет связь WSAEventSelecthEventObject с FD_ACCEPT, FD_READ и FD_WRITE, то любой сокет, принятый в этом сокете прослушивания, также будет иметь FD_ACCEPT, FD_READ и FD_WRITE сетевые события, связанные с тем же hEventObject. Если требуются другие события hEventObject или сетевые события, приложение должно вызвать WSAEventSelect, передав принятый сокет и нужные новые сведения.

Пример кода

В следующем примере показано использование функции WSAEventSelect .
//-------------------------
// Declare and initialize variables
SOCKET ListenSocket;
WSAEVENT NewEvent;
sockaddr_in InetAddr;

//-------------------------
// Initialize listening socket
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

//-------------------------
// Bind listening socket
InetAddr.sin_family = AF_INET;
InetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InetAddr.sin_port = htons(27015);

bind (ListenSocket, (SOCKADDR *) &InetAddr, sizeof(InetAddr));

//-------------------------
// Create new event
NewEvent = WSACreateEvent();

//-------------------------
// Associate event types FD_ACCEPT and FD_CLOSE
// with the listening socket and NewEvent
WSAEventSelect( ListenSocket, NewEvent, FD_ACCEPT | FD_CLOSE);

//----------------------
// Listen for incoming connection requests 
// on the created socket
if (listen( ListenSocket, SOMAXCONN ) == SOCKET_ERROR)
    printf("Error listening on socket.\n");

printf("Listening on socket...\n");

// Need an event handler added to handle connection requests



Windows Phone 8. Эта функция поддерживается для приложений Магазина Windows Phone на Windows Phone 8 и более поздних версиях.

Windows 8.1 и Windows Server 2012 R2. Эта функция поддерживается для приложений Магазина Windows на Windows 8.1, Windows Server 2012 R2 и более поздних версиях.

Требования

Требование Значение
Минимальная версия клиента Windows 8.1, Windows Vista [классические приложения | Приложения UWP]
Минимальная версия сервера Windows Server 2003 [классические приложения | Приложения UWP]
Целевая платформа Windows
Header winsock2.h
Библиотека Ws2_32.lib
DLL Ws2_32.dll

См. также раздел

WSAsyncSelect

WSACloseEvent

WSACreateEvent

WSAEnumNetworkEvents

WSAWaitForMultipleEvents

Функции Winsock

Справочник по Winsock

shutdown