Поделиться через


Функция WSAAsyncSelect (winsock.h)

[Функция WSAsyncSelect доступна для использования в операционных системах, указанных в разделе Требования. В последующих версиях он может быть изменен или недоступен. Вместо использования операций ввода-вывода в стиле выбора используйте перекрывающиеся объекты ввода-вывода и объекты событий с WinSock2.]

Функция WSAsyncSelect запрашивает уведомления Windows на основе сообщений о сетевых событиях для сокета.

Синтаксис

int WSAAsyncSelect(
  [in] SOCKET s,
  [in] HWND   hWnd,
  [in] u_int  wMsg,
  [in] long   lEvent
);

Параметры

[in] s

Дескриптор, определяющий сокет, для которого требуется уведомление о событии.

[in] hWnd

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

[in] wMsg

Сообщение, которое должно быть получено при возникновении сетевого события.

[in] lEvent

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

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

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

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

При получении сообщения в окне приложения можно задать дополнительные коды ошибок. Этот код ошибки извлекается из lParam в ответном сообщении с помощью макроса WSAGETSELECTERROR . Возможные коды ошибок для каждого сетевого события перечислены в следующей таблице.

Событие: FD_CONNECT

Код ошибки Значение
WSAEAFNOSUPPORT Адреса из заданного семейства адресов не могут использоваться с этим сокетом.
WSAECONNREFUSED Попытка подключения отклонена.
WSAENETUNREACH В настоящее время сеть недоступна с этого узла.
WSAEFAULT Недопустимый параметр namelen .
WSAEINVAL Сокет уже привязан к адресу.
WSAEISCONN Сокет уже подключен.
WSAEMFILE Больше нет доступных дескрипторов файлов.
WSAENOBUFS Нет свободного места в буфере. Не удается подключить сокет.
WSAENOTCONN Сокет не подключен.
WSAETIMEDOUT Попытка подключения истекло, не устанавливая подключение.
 

Событие: FD_CLOSE

Код ошибки Значение
WSAENETDOWN Произошел сбой сетевой подсистемы.
WSAECONNRESET Подключение было сброшено удаленной стороной.
WSAECONNABORTED Подключение было прервано из-за истечения времени ожидания или другого сбоя.
 
Код ошибки Значение
WSAENETDOWN Произошел сбой сетевой подсистемы.
 

Событие: FD_ROUTING_INTERFACE_CHANGE

Код ошибки Значение
WSAENETUNREACH Указанное назначение больше недоступно.
WSAENETDOWN Произошел сбой сетевой подсистемы.

Комментарии

Функция WSAsyncSelect используется для запроса того, чтобы WS2_32.DLL отправляли сообщение в окно hWnd при обнаружении любого сетевого события, указанного параметром lEvent . Сообщение, которое должно быть отправлено, указывается параметром wMsg . Сокет, для которого требуется уведомление, определяется параметром s .

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

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

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

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

rc = WSAAsyncSelect(s, hWnd, wMsg, FD_READ|FD_WRITE);

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

rc = WSAAsyncSelect(s, hWnd, wMsg1, FD_READ);
rc = WSAAsyncSelect(s, hWnd, wMsg2, FD_WRITE);

Чтобы отменить все уведомления о том, что сокеты Windows не должны отправлять дальнейшие сообщения, связанные с сетевыми событиями в сокете, для параметра lEvent задано значение 0.

rc = WSAAsyncSelect(s, hWnd, 0, 0);

Хотя WSAsyncSelect немедленно отключает отправку сообщений о событиях для сокета в этом экземпляре, вполне возможно, что сообщения могут находиться в очереди сообщений приложения. Поэтому приложение должно быть готово к получению сообщений о сетевых событиях даже после отмены. Закрытие сокета с помощью closesocket также отменяет отправку сообщений WSAsyncSelect , но те же предупреждения о сообщениях в очереди по-прежнему применяются.

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

Если одно из назначенных сетевых событий происходит в указанных сокетах, окно приложения hWnd получает сообщение wMsg. Параметр wParam определяет сокет, в котором произошло сетевое событие. Низкое слово lParam указывает сетевое событие, которое произошло. Высокое слово lParam содержит любой код ошибки. Код ошибки — любая ошибка, определенная в Winsock2.h.

Примечание После получения сообщения уведомления о событии функцию WSAGetLastError нельзя использовать для проверка значения ошибки, так как возвращаемое значение ошибки может отличаться от значения в слове lParam высокого уровня.
 
Коды ошибок и событий можно извлечь из lParam с помощью макросов WSAGETSELECTERROR и WSAGETSELECTEVENT, определенных в Winsock2.h как:
#include <windows.h>

#define WSAGETSELECTEVENT(lParam)       LOWORD(lParam)
#define WSAGETSELECTERROR(lParam)       HIWORD(lParam)

Использование этих макросов обеспечит максимальную переносимость исходного кода для приложения.

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

Значение Значение
FD_READ Сокеты готовы к чтению.
FD_WRITE Сокеты готовы к записи.
FD_OOB Данные OOB готовы к чтению в сокетах
FD_ACCEPT Сокеты готовы к принятию нового входящего подключения.
FD_CONNECT Операция подключения или многоточечных соединений , инициированная по завершению сокетов .
FD_CLOSE Подключение, определенное по сокетам , было закрыто.
FD_QOS Качество обслуживания, связанное с сокетами , изменилось.
FD_GROUP_QOS Зарезервировано. Качество обслуживания, связанное с группой сокетов , к которой принадлежит , изменилось (зарезервировано для будущего использования с группами сокетов).
FD_ROUTING_INTERFACE_CHANGE Изменен локальный интерфейс, который должен использоваться для отправки в указанное место назначения.
FD_ADDRESS_LIST_CHANGE Изменен список адресов семейства протоколов сокетов, к которым может привязаться клиент приложения.
 

Хотя WSAAsyncSelect можно вызывать с интересом к нескольким событиям, окно приложения будет получать одно сообщение для каждого сетевого события.

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

  1. Данные поступают в сокеты; Сообщения WSAsyncSelect для сокетов Windows 2
  2. Приложение обрабатывает другое сообщение
  3. Во время обработки приложение выдает ioctlsocket(s, FIONREAD...) и замечает, что данные готовы к чтению
  4. Приложение выдает для recv(s,...) чтения данных
  5. Циклы приложения для обработки следующего сообщения, в конечном итоге достигая сообщения WSAsyncSelect , указывающего, что данные готовы к чтению
  6. Проблемы recv(s,...)с приложением, которые завершаются сбоем с ошибкой WSAEWOULDBLOCK.
Также возможны другие последовательности.

WS2_32.DLL не будет постоянно заполнять приложение сообщениями для определенного сетевого события. После успешной публикации уведомления о конкретном событии в окне приложения дальнейшие сообщения для этого сетевого события не будут отправляться в окно приложения, пока приложение не выполнит вызов функции, который неявно повторно включает уведомление об этом сетевом событии.

Событие Функция reenabling
FD_READ recv, recvfrom, WSARecv или WSARecvFrom.
FD_WRITE send, sendto, WSASend или WSASendTo.
FD_OOB recv, recvfrom, WSARecv или WSARecvFrom.
FD_ACCEPT accept или WSAAccept, если код ошибки не WSATRY_AGAIN , указывающий, что функция условия вернула CF_DEFER.
FD_CONNECT Нет.
FD_CLOSE Нет.
FD_QOS WSAIoctl с командой SIO_GET_QOS.
FD_GROUP_QOS Зарезервировано. WSAIoctl с командой SIO_GET_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 публикация сообщений активируется на уровне. Это означает, что если вызывается подпрограмма повторного добавления и соответствующее условие по-прежнему выполняется после вызова, в приложение отправляется сообщение WSAsyncSelect . Это позволяет приложению управлять событиями и не беспокоиться о количестве данных, поступающих в любой момент времени. Рассмотрим следующую последовательность:

  1. Стек сетевого транспорта получает 100 байт данных в сокетах и заставляет Windows Sockets 2 публиковать FD_READ сообщение.
  2. Приложение выдает recv( s, buffptr, 50, 0) для чтения 50 байт.
  3. Публикуется еще одно сообщение FD_READ , так как все еще есть данные для чтения.
При такой семантике приложению не требуется считывать все доступные данные в ответ на сообщение FD_READ — в ответ на каждое FD_READ сообщение подходит один прямой ответ. Если приложение отправляет несколько вызовов recv в ответ на один FD_READ, оно может получать несколько FD_READ сообщений. Такое приложение может потребовать отключения FD_READ сообщений перед началом вызовов recv путем вызова WSAAsyncSelect с не заданным событием FD_READ .

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

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

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

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

  1. Вызовы приложения прослушивают.
  2. Запрос на подключение получен, но еще не принят.
  3. Приложение вызывает WSAsyncSelect , указывая, что требуется получать FD_ACCEPT сообщения для сокета. Из-за сохраняемости событий Windows Sockets 2 немедленно публикует сообщение FD_ACCEPT .

Событие FD_WRITE обрабатывается немного иначе. Сообщение FD_WRITE публикуется, когда сокет сначала подключается с помощью connect или WSAConnect (после FD_CONNECT, если также зарегистрирован) или принимается с помощью accept или 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. Это приводит к тому, что удаленный конец выполняет завершение работы на стороне отправки или closesocket. FD_CLOSE следует публиковать только после того, как все данные считываются из сокета, но приложение должно проверка для оставшихся данных при получении FD_CLOSE, чтобы избежать любой возможности потери данных.

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

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

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

Ниже приведена сводка событий и условий для каждого асинхронного уведомления.

  • FD_READ:
    1. При вызове метода WSAsyncSelect , если есть данные, доступные для получения в настоящее время.
    2. При поступлении данных, если FD_READ еще не опубликовано.
    3. После вызова recv или recvfrom с MSG_PEEK или без нее), если данные по-прежнему доступны для получения.
      Примечание Если параметр setsockopt SO_OOBINLINE включен, данные включают как обычные данные, так и данные OOB в указанных выше экземплярах.
       
  • FD_WRITE:
    1. При вызове метода WSAsyncSelect можно ли выполнить отправку или отправку .
    2. После подключения или принятия вызова, когда подключение установлено.
    3. После отправки или отправки сбойс WSAEWOULDBLOCK, когда отправка или отправка, скорее всего, завершится успешно.
    4. После привязки к сокету без подключения. FD_WRITE может возникнуть или не происходить в настоящее время (зависит от реализации). В любом случае сокет без подключения всегда доступен для записи сразу после операции привязки .
  • FD_OOB: допустимо только в том случае, если параметр setsockopt SO_OOBINLINE отключен (по умолчанию).
    1. Если при вызове метода WSAAsyncSelect есть данные OOB, доступные для получения с флагом MSG_OOB.
    2. При поступлении данных OOB, если FD_OOB еще не опубликовано.
    3. После вызова recv или recvfrom с флагом MSG_OOB или без нее, если данные OOB по-прежнему доступны для получения.
  • FD_ACCEPT:
    1. При вызове метода WSAAsyncSelect , если в настоящее время есть запрос на подключение, доступный для принятия.
    2. При поступлении запроса на подключение, если FD_ACCEPT еще не опубликовано.
    3. После вызова accept , если есть другой запрос на подключение, доступный для принятия.
  • FD_CONNECT:
    1. При вызове метода WSAsyncSelect , если подключение установлено в данный момент.
    2. После вызова подключения подключение устанавливается, даже если подключение выполняется немедленно, как это характерно для сокета датаграммы.
    3. После вызова WSAJoinLeaf, когда операция соединения завершается.
    4. После подключения был вызван WSAConnect или WSAJoinLeaf с неблокированным сокетом, ориентированным на подключение. Исходная операция была возвращена с определенной ошибкой WSAEWOULDBLOCK, но сетевая операция была выполнена. Независимо от того, завершается ли операция успешной или нет, когда результат определен, FD_CONNECT происходит. Клиент должен проверка код ошибки, чтобы определить, был ли результат успешным или неудачным.
  • FD_CLOSE: допустимо только для сокетов, ориентированных на подключение (например, SOCK_STREAM).
    1. При вызове метода WSAAsyncSelect , если подключение к сокету закрыто.
    2. После того, как удаленная система инициировала корректное закрытие, если данные в настоящее время недоступны для получения (имейте в виду, что если данные были получены и ожидают чтения, когда удаленная система инициирует корректное закрытие, FD_CLOSE не будет доставлена до тех пор, пока не будут прочитаны все ожидающие данные).
    3. После того как локальная система инициирует корректное закрытие с завершением работы , и удаленная система ответила уведомлением "Конец данных" (например, TCP FIN), если данные в настоящее время недоступны для получения.
    4. Когда удаленная система завершает подключение (например, отправлено TCP RST), и lParam будет содержать значение ошибки WSAECONNRESET .
      ПримечаниеFD_CLOSE не публикуется после вызова closesocket .
       
  • FD_QOS:
    1. При вызове метода WSAsyncSelect , если качество обслуживания, связанного с сокетом, было изменено.
    2. После вызова WSAIoctl с SIO_GET_QOS при изменении качества обслуживания.
  • FD_GROUP_QOS: зарезервировано.
  • FD_ROUTING_INTERFACE_CHANGE:
    • После вызова WSAIoctl с SIO_ROUTING_INTERFACE_CHANGE, когда изменяется локальный интерфейс, который должен использоваться для достижения назначения, указанного в IOCTL.
  • FD_ADDRESS_LIST_CHANGE:
    • После вызова WSAIoctl с SIO_ADDRESS_LIST_CHANGE при изменении списка локальных адресов, к которым может привязаться приложение.

Требования

Требование Значение
Минимальная версия клиента Windows 2000 Professional [только классические приложения]
Минимальная версия сервера Windows 2000 Server [только классические приложения]
Целевая платформа Windows
Header winsock.h (включая Winsock2.h)
Библиотека Ws2_32.lib
DLL Ws2_32.dll

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

WSAEventSelect

Функции Winsock

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

select