WSAAsyncSelect 函数 (winsock.h)

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

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

语法

int 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 来检索特定的错误号。

错误代码 含义
WSANOTINITIALISED
在使用此函数之前,必须成功调用 WSAStartup
WSAENETDOWN
网络子系统失败。
WSAEINVAL
指定参数之一无效,例如窗口句柄未引用现有窗口,或者指定的套接字处于无效状态。
WSAEINPROGRESS
阻止 Windows Sockets 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 参数标识。

无论 lEvent 的值如何,WSAAsyncSelect 函数都会自动将套接字 设置为非阻止模式。 若要 将套接字设置 回阻止模式,首先 需要通过调用WSAAsyncSelect 清除与套接字 关联的事件记录,并将 lEvent 设置为零。 然后,可以调用 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 将取消同一套接字的任何以前的 WSAsyncSelectWSAEventSelect 。 例如,若要接收读取和写入通知,应用程序必须使用 FD_READFD_WRITE 调用 WSAsyncSelect,如下所示:

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 将接收 wMsg 消息wParam 参数标识发生了网络事件的套接字。 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. 应用程序循环处理下一条消息,最终到达 WSAsyncSelect 消息,指示数据已准备好读取
  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 ( sbuffptr、50、0) 以读取 50 个字节。
  3. 发布另一条 FD_READ 消息,因为仍有要读取的数据。
借助这些语义,应用程序无需读取所有可用数据即可响应FD_READ消息,因此只需对每个FD_READ消息进行一次响应。 如果应用程序发出多个 recv 调用以响应单个 FD_READ,它可以接收多个 FD_READ 消息。 此类应用程序可能需要在启动 recv 调用之前禁用FD_READ消息,方法是调用 WSAAsyncSelect,但未设置 FD_READ 事件。

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

发出 此类 IOCTL 后,当用于访问 WSAIoctl 中指定的目标的本地接口SIO_ROUTING_INTERFACE_CHANGE更改时,将发布FD_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 (连接时,如果也注册) 或接受接受,则在发送操作失败且 WSAEWOULDBLOCK 且缓冲区空间变为可用之后,将发布FD_WRITE消息。 因此,应用程序可以假设发送可能从第一 个FD_WRITE 消息开始,一直持续到发送返回 WSAEWOULDBLOCK。 发生此类故障后,应用程序将收到通知,指出可以通过 FD_WRITE 消息再次发送。

仅当套接字配置为单独接收 OOB 数据时,才使用 FD_OOB 事件。 如果套接字配置为接收内联 OOB 数据,则 OOB (加速) 数据被视为正常数据,应用程序应注册一个兴趣,并接收 FD_READ 事件,而不是 FD_OOB 事件。 应用程序可以使用 setockoptgetsockopt for 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结合使用,以便分别获取套接字 s 或套接字组所属 当前服务质量。

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. 发送sendto 失败并出现 WSAEWOULDBLOCK 后,当 sendsendto 可能成功时。
    4. 在无连接套接字上 绑定 后。 此时, ( 依赖于实现的) 发生FD_WRITE,也可能不发生。 在任何情况下,无连接套接字始终在 绑定 操作后立即可写。
  • FD_OOB:仅在禁用 setockopt SO_OOBINLINE (默认) 时才有效。
    1. 调用 WSAAsyncSelect 时,如果当前有可以使用 MSG_OOB 标志接收的 OOB 数据。
    2. 当 OOB 数据到达时, 如果FD_OOB 尚未发布。
    3. 使用或不带MSG_OOB标志调用的 recvrecvfrom 之后,如果仍可接收 OOB 数据,则为 。
  • FD_ACCEPT
    1. 调用 WSAAsyncSelect 时,如果当前存在可接受的连接请求。
    2. 当连接请求到达时, 如果FD_ACCEPT 尚未发布。
    3. 接受 调用后,如果有另一个连接请求可供接受。
  • 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
标头 winsock.h (包括 Winsock2.h)
Library Ws2_32.lib
DLL Ws2_32.dll

另请参阅

WSAEventSelect

Winsock 函数

Winsock 参考

select