WSAAsyncSelect 函数 (winsock2.h)

[ WSAAsyncSelect 函数可用于“要求”部分中指定的操作系统。 它可能在后续版本中变更或不可用。 将 重叠 I/O 和事件对象 与 WinSock2 配合使用,而不是使用 Select-style I/O。]

WSAAsyncSelect 函数请求针对套接字的网络事件发出基于 Windows 消息的通知。

语法

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

参数

[in] s

标识需要事件通知的套接字的描述符。

[in] hWnd

标识在发生网络事件时接收消息的窗口的句柄。

[in] wMsg

发生网络事件时要接收的消息。

[in] lEvent

位掩码,指定应用程序感兴趣的网络事件的组合。

返回值

如果 WSAAsyncSelect 函数成功,则返回值为零,前提是应用程序对网络事件集的兴趣声明成功。 否则,将返回值SOCKET_ERROR,并且可以通过调用 WSAGetLastError 检索特定的错误号。

错误代码 含义
WSANOTINITIALIZED
在使用此函数之前,必须成功调用 WSAStartup
WSAENETDOWN
网络子系统失败。
WSAEINVAL
指定参数之一无效,例如窗口句柄未引用现有窗口,或者指定的套接字处于无效状态。
WSAEINPROGRESS
阻止 Windows 套接字 1.1 调用正在进行,或者服务提供商仍在处理回调函数。
WSAENOTSOCK
:描述符不是套接字。
 

当应用程序窗口收到消息时,可以设置其他错误代码。 此错误代码是使用 WSAGETSELECTERROR 宏从回复消息中的 lParam 中提取的。 下表列出了每个网络事件的可能错误代码。

事件: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 网络子系统失败。

注解

WSAAsyncSelect 函数用于请求 WS2_32.DLL 在检测到由 lEvent 参数指定的任何网络事件时应向窗口 hWnd 发送消息。 应发送的消息由 wMsg 参数指定。 需要通知的套接字由 s 参数标识。

WSAAsyncSelect 函数自动将套接字设置为非阻止模式,而不考虑 lEvent 的值。 若要 将套接字重新 设置为阻止模式,首先 需要通过调用WSAAsyncSelectlEvent 设置为零)来清除与套接字关联的事件记录。 然后,可以调用 ioctlsocketWSAIoctl ,将套接字重新设置为阻止模式。 有关如何将非阻止套接字设置回阻止模式的详细信息,请参阅 ioctlsocketWSAIoctl 函数。

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 想要接收套接字协议系列的本地地址列表更改通知。
 

为套接字发出 WSAAsyncSelect 会取消同一套接字的任何以前的 WSAAsyncSelectWSAEventSelect 。 例如,若要接收读取和写入通知,应用程序必须使用 FD_READFD_WRITE调用 WSAAsyncSelect,如下所示:

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 设置为零。

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

尽管 WSAAsyncSelect 在此实例中立即禁用套接字的事件消息发布,但消息可能在应用程序消息队列中等待。 因此,应用程序必须准备好在取消后接收网络事件消息。 使用 closesocket 关闭套接字也会取消 WSAAsyncSelect 消息发送,但队列中有关消息的相同警告仍然适用。

由 accept 函数创建的套接字与用于接受它的侦听套接字具有相同的属性。 因此,为侦听套接字设置 的 WSAAsyncSelect 事件也适用于接受的套接字。 例如,如果侦听套接字具有 WSAAsyncSelect 事件 FD_ACCEPTFD_READFD_WRITE,则该侦听套接字上接受的任何套接字也将具有 FD_ACCEPTFD_READFD_WRITE 事件,这些事件具有相同的 wMsg 值用于消息。 如果需要其他 wMsg 或事件,应用程序应调用 WSAAsyncSelect,传递接受的套接字和所需的新数据。

当指定网络事件之一在 指定的套接字上发生时,应用程序窗口 hWnd 将接收 消息 wMsgwParam 参数标识发生了网络事件的套接字。 lParam 的低字指定已发生的网络事件。 lParam 的高字包含任何错误代码。 错误代码是 Winsock2.h 中定义的任何错误。

注意收到事件通知消息后,WSAGetLastError 函数不能用于检查错误值,因为返回的错误值可能与 lParam 高字中的值不同。
 
可以使用 Winsock2.h 中定义的宏 WSAGETSELECTERRORWSAGETSELECTEVENTlParam 中提取错误和事件代码:
#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 函数一样, WSAAsyncSelect 将经常用于确定何时可以发出 (发送接收) 的数据传输操作,并期望立即成功。 但是,可靠的应用程序必须做好准备,使其可能收到消息并发出立即返回 WSAEWOULDBLOCK 的 Windows 套接字 2 调用。 例如,可以按以下顺序排列事件:

  1. 数据通过套接字 到达;Windows 套接字 2 发布 WSAAsyncSelect 消息
  2. 应用程序处理其他一些消息
  3. 处理时,应用程序会发出 , ioctlsocket(s, FIONREAD...) 并通知有数据可供读取
  4. 应用程序发出 读取 recv(s,...) 数据的
  5. 应用程序循环处理下一条消息,最终到达 WSAAsyncSelect 消息,指示数据已准备好读取
  6. 应用程序问题 recv(s,...),失败并出现 错误 WSAEWOULDBLOCK
还可以使用其他序列。

WS2_32.DLL 不会持续向应用程序填充特定网络事件的消息。 成功将特定事件的通知发布到应用程序窗口后,在应用程序调用该网络事件的隐式重新通知的函数之前,不会再向应用程序窗口发布任何消息 (该网络事件的) 。

事件 重新启用函数
FD_READ recvrecvfromWSARecvWSARecvFrom
FD_WRITE sendsendtoWSASendWSASendTo
FD_OOB recvrecvfromWSARecvWSARecvFrom
FD_ACCEPT acceptWSAAccept ,除非错误代码 WSATRY_AGAIN 指示条件函数返回CF_DEFER。
FD_CONNECT 无。
FD_CLOSE 无。
FD_QOS 具有命令SIO_GET_QOS的 WSAIoctl
FD_GROUP_QOS 保留。 带有命令的 WSAIoctl SIO_GET_GROUP_QOS (保留供将来使用,套接字组) 。
FD_ROUTING_INTERFACE_CHANGE 具有命令SIO_ROUTING_INTERFACE_CHANGE的 WSAIoctl
FD_ADDRESS_LIST_CHANGE 具有命令SIO_ADDRESS_LIST_CHANGE的 WSAIoctl
 

对重新启用例程的任何调用(即使是失败的调用)都会导致重新启用相关事件的消息发布。

对于 FD_READFD_OOBFD_ACCEPT 事件,消息发布是级别触发的。 这意味着,如果调用重新启用例程,并且调用后仍满足相关条件,则会将 WSAAsyncSelect 消息发布到应用程序。 这样,应用程序就可以由事件驱动,而不必担心某个时间到达的数据量。 考虑以下序列:

  1. 网络传输堆栈 在套接字上 接收 100 字节的数据,并导致 Windows 套接字 2 发布 FD_READ 消息。
  2. 应用程序发出 recv (buffptr、50、0) 读取 50 个字节。
  3. 发布另一 条FD_READ 消息,因为仍有数据要读取。
借助这些语义,应用程序不需要读取所有可用数据来响应FD_READ消息,因此只需一个响应FD_READ消息即可。 如果应用程序发出多个 recv 调用以响应单个 FD_READ,它可以接收多个 FD_READ 消息。 此类应用程序可能需要禁用FD_READ消息,然后通过调用 WSAAsyncSelect 来启动 recv 调用,但未设置 FD_READ 事件。

FD_QOSFD_GROUP_QOS事件被视为边缘触发的。 当发生服务质量更改时,消息将恰好发布一次。 在提供程序检测到服务质量的进一步更改或应用程序重新协商套接字的服务质量之前,不会再发送其他消息。

发布 FD_ROUTING_INTERFACE_CHANGE 消息时,应用于访问 WSAIoctl 中指定的目标的本地接口,并在发出此类 IOCTL 后SIO_ROUTING_INTERFACE_CHANGE更改。

发出 WSAIoctlSIO_ADDRESS_LIST_CHANGE 后,当应用程序可以绑定到的地址列表更改时,将发布FD_ADDRESS_LIST_CHANGE消息。

如果在应用程序调用 WSAAsyncSelect 或调用重新启用函数时发生任何事件,则会根据需要发布一条消息。 例如,请看下面的序列:

  1. 应用程序调用 listen
  2. 已收到连接请求,但尚未接受。
  3. 应用程序调用 WSAAsyncSelect ,指定它需要接收套接字 FD_ACCEPT 消息。 由于事件的持久性,Windows 套接字 2 会立即发布 FD_ACCEPT 消息。
FD_WRITE 事件的处理方式略有不同。 在 FD_CONNECT 后首次使用 connectWSAConnect (连接套接字时,如果也注册) 或通过 acceptWSAAccept 接受,则在发送操作失败并显示 WSAEWOULDBLOCK 且缓冲区空间变得可用后,将发布FD_WRITE消息。 因此,应用程序可以假设可以从第一个 FD_WRITE 消息开始发送,一直持续到发送返回 WSAEWOULDBLOCK。 发生此类故障后,应用程序将收到通知,告知可能再次发送 FD_WRITE 消息。

仅当套接字配置为单独接收 OOB 数据时,才使用 FD_OOB 事件。 如果套接字配置为内联接收 OOB 数据,则 OOB (加速) 数据被视为正常数据,应用程序应注册对事件的兴趣,并将接收 FD_READ 事件,而不是 FD_OOB 事件。 应用程序可以使用 setsockoptgetsockopt 作为 SO_OOBINLINE 选项来设置或检查 OOB 数据的处理方式。

FD_CLOSE消息中的错误代码指示套接字关闭是正常还是中止。 如果错误代码为零,则关闭正常;如果错误代码为 WSAECONNRESET,则表示套接字的虚拟线路已重置。 这仅适用于面向连接的套接字,例如SOCK_STREAM。

收到对应于套接字的虚拟线路的关闭指示时,将发布FD_CLOSE消息。 在 TCP 术语中,这意味着当连接进入 TIME WAIT 或 CLOSE WAIT 状态时,将发布 FD_CLOSE 。 这源于远程端在发送端或关闭端执行关闭操作。 FD_CLOSE应仅在从套接字读取所有数据后发布,但应用程序应在收到FD_CLOSE后检查剩余数据,以避免丢失数据的可能性。

请注意,应用程序将仅收到指示虚拟线路关闭 的FD_CLOSE 消息,并且仅当已读取所有接收的数据时,才会正常关闭。 它不会收到指示此条件 的FD_READ 消息。

与套接字 或所属套接字组关联的流规范中的任何参数发生更改时,将分别发布FD_QOS或FD_GROUP_QOS消息。 应用程序应将 WSAIoctl 与命令SIO_GET_QOS或SIO_GET_GROUP_QOS结合使用,分别 获取套接字或 套接字组 所属 当前服务质量。

FD_ROUTING_INTERFACE_CHANGEFD_ADDRESS_LIST_CHANGE事件也被视为边缘触发事件。 在应用程序请求通知后,如果发生更改,则会恰好发布一次消息,并相应地向 WSAIoctl 发出SIO_ROUTING_INTERFACE_CHANGE或SIO_ADDRESS_LIST_CHANGE。 在应用程序重新发出 IOCTL 并检测到另一个更改之前,不会收到其他消息,因为已发出 IOCTL。

下面是每个异步通知消息的事件和条件的摘要。

  • FD_READ
    1. 调用 WSAAsyncSelect 时,如果当前有数据可供接收。
    2. 数据到达时(如果 尚未发布FD_READ )。
    3. 调用 recvrecvfrom 后,如果数据仍可供接收,则带或不带MSG_PEEK) 。
      注意 启用 setsockopt SO_OOBINLINE 后,数据包括上述实例中的普通数据和 OOB 数据。
       
  • FD_WRITE
    1. WSAAsyncSelect 调用时,如果可以 发送sendto
    2. 连接接受调用后,建立连接时。
    3. 在 sendsendto 失败并出现 WSAEWOULDBLOCK 之后,当 sendsendto 可能成功时。
    4. 在无连接套接字上 绑定 后。 此时, ( 依赖于实现的) FD_WRITE可能会发生,也可能不发生。 在任何情况下,无连接套接字始终在 绑定 操作后立即可写。
  • FD_OOB:仅在禁用 setsockopt SO_OOBINLINE 时有效, (默认) 。
    1. WSAAsyncSelect 调用时,如果当前有可以使用 MSG_OOB 标志接收的 OOB 数据。
    2. 当 OOB 数据到达时( 如果FD_OOB 尚未发布)。
    3. recvrecvfrom 调用后,如果 OOB 数据仍可供接收,则MSG_OOB标志。
  • FD_ACCEPT
    1. WSAAsyncSelect 调用时,如果当前有可供接受的连接请求。
    2. 当连接请求到达时,如果 FD_ACCEPT 尚未发布。
    3. 调用 accept 后,如果有另一个连接请求可供接受。
  • FD_CONNECT
    1. WSAAsyncSelect 调用时,如果当前已建立连接。
    2. 调用 连接 后,建立连接时,即使 连接 立即成功,就像数据报套接字的典型情况一样。
    3. 调用 WSAJoinLeaf 后,当联接操作完成时。
    4. 连接后,WSAConnectWSAJoinLeaf 是使用非阻止的、面向连接的套接字调用的。 初始操作返回并显示 WSAEWOULDBLOCK 的特定错误,但网络操作继续进行。 无论操作最终是否成功,在确定结果后, FD_CONNECT 发生。 客户端应检查错误代码,以确定结果是成功还是失败。
  • FD_CLOSE:仅在面向连接的套接字 (有效,例如,SOCK_STREAM)
    1. WSAAsyncSelect 调用时,如果套接字连接已关闭,则为 。
    2. 远程系统启动正常关闭后,如果当前没有可用于接收的数据 (请注意,如果已收到数据并在远程系统启动正常关闭时等待读取,则在读取所有挂起的数据) 之前,不会传送 FD_CLOSE
    3. 在本地系统启动正常 关闭并关闭 后,远程系统响应了“数据结束”通知 (例如 TCP FIN) ,但当前没有数据可供接收。
    4. 例如,当远程系统终止连接 (发送的 TCP RST ) ,lParam 将包含 WSAECONNRESET 错误值。
      请注意,调用closesocket 后不会发布FD_CLOSE。
       
  • FD_QOS
    1. WSAAsyncSelect 调用时,与套接字关联的服务质量是否已更改。
    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
标头 winsock2.h (包括 Winsock2.h)
Library Ws2_32.lib
DLL Ws2_32.dll

另请参阅

WSAEventSelect

Winsock 函数

Winsock 参考

select