相关文章推荐
文雅的登山鞋  ·  uitextview删除文字 ...·  2 月前    · 
文质彬彬的酸菜鱼  ·  ORA-00920: ...·  1 年前    · 
任性的小马驹  ·  .net core web api ...·  1 年前    · 
怕老婆的课本  ·  前端 - ...·  1 年前    · 

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

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

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

事件:FD_CONNECT

WSAEAFNOSUPPORT 指定系列中的地址无法与此套接字一起使用。 WSAECONNREFUSED :连接尝试被拒绝。 WSAENETUNREACH 此时不可以从此主机访问该网络。 WSAEFAULT namelen 参数无效。 WSAEINVAL :套接字已绑定到地址。 WSAEISCONN :套接字已连接。 WSAEMFILE 没有更多可用的文件描述符。 WSAENOBUFS 未提供任何缓冲区空间。 无法连接套接字。 WSAENOTCONN 套接字未连接。 WSAETIMEDOUT :连接尝试超时,没有建立连接。

事件:FD_CLOSE

WSAENETDOWN 网络子系统失败。 WSAECONNRESET :此连接已由远端重置。 WSAECONNABORTED 由于超时或其他故障,连接已终止。

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

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

lEvent 参数是使用按位 OR 运算符构造的,其中包含下表中列出的任何值。

Value 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);

无法为不同的事件指定不同的消息。 以下代码不起作用;第二个调用将取消第一个调用的效果,并且只会报告带有消息 wMsg2 的FD_WRITE 事件:

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,则在该侦听套接字上接受的任何套接字也将具有用于消息的相同 wMsg 值FD_ACCEPT、FD_READFD_WRITE事件。 如果需要其他 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)

使用这些宏将最大程度地提高应用程序的源代码的可移植性。

下表列出了可返回的网络事件代码。

Value 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 可以针对多个事件感兴趣调用,但应用程序窗口将为每个网络事件接收一条消息。

选择 函数一样, WSAAsyncSelect 将经常用于确定数据传输操作何时 (发送recv) 可以立即成功。 但是,必须准备好可靠的应用程序,以便它可以接收消息并发出 Windows 套接字 2 调用,以便立即返回 WSAEWOULDBLOCK 。 例如,可以使用以下事件序列:

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

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

    重新启用函数 FD_READ recvrecvfromWSARecvWSARecvFromFD_WRITE send、sendtoWSASendWSASendToFD_OOB recvrecvfromWSARecvWSARecvFromFD_ACCEPT 接受WSAAccept ,除非错误代码 WSATRY_AGAIN 指示条件函数返回CF_DEFER。 FD_CONNECT FD_CLOSE FD_QOS 具有命令SIO_GET_QOS的 WSAIoctlFD_GROUP_QOS 使用命令SIO_GET_GROUP_QOS (保留 WSAIoctl,以便将来与套接字组一起使用) 。 FD_ROUTING_INTERFACE_CHANGE 具有命令SIO_ROUTING_INTERFACE_CHANGE的 WSAIoctlFD_ADDRESS_LIST_CHANGE 具有命令SIO_ADDRESS_LIST_CHANGE的 WSAIoctl

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

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

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

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

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

    发布 FD_ADDRESS_LIST_CHANGE 消息时,应用程序可以在发出 SIO_ADDRESS_LIST_CHANGE WSAIoctl 之后绑定更改的地址列表。

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

  • 应用程序调用 侦听
  • 收到连接请求,但尚未接受。
  • 应用程序调用 WSAAsyncSelect ,指定它需要接收套接字 的FD_ACCEPT 消息。 由于事件的持久性,Windows 套接字 2 会立即发布 FD_ACCEPT 消息。
  • FD_WRITE事件处理方式略有不同。 当套接字首次连接到连接WSAConnect (后,如果 FD_CONNECT还注册了) 或接受了接受WSAAccept,则在发送操作失败且 WSAEWOULDBLOCK 和缓冲区空间可用时,将发布FD_WRITE消息。 因此,应用程序可以假定从第一条 FD_WRITE 消息开始发送,直到发送返回 WSAEWOULDBLOCK 为止。 发生此类故障后,应用程序将收到通知,即使用 FD_WRITE 消息再次发送。

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

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

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

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

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

    FD_ROUTING_INTERFACE_CHANGEFD_ADDRESS_LIST_CHANGE事件也被视为触发边缘。 当应用程序请求通知通知后,应用程序发出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 数据。
    4. WSAAsyncSelect 调用时,如果有可能 发送sendto
    5. 连接接受调用后,建立连接时。
    6. 发送sendto 失败且 WSAEWOULDBLOCK 失败后,发送sendto 可能会成功。
    7. 在无连接套接字上 绑定 后。 FD_WRITE 目前可能或可能不会发生 (依赖实现的) 。 在任何情况下,在 绑定 操作后,无连接套接字始终可立即写入。
    8. FD_OOB:仅在默认) (禁用 setsockopt SO_OOBINLINE时才有效。
    9. WSAAsyncSelect 调用时,如果有 OOB 数据当前可用于接收MSG_OOB标志。
    10. 当 OOB 数据到达时,如果 尚未发布FD_OOB
    11. 使用或不带MSG_OOB标志调用 recvrecvfrom 后,如果 OOB 数据仍可供接收。
    12. FD_ACCEPT
      1. WSAAsyncSelect 调用时,如果当前有一个可供接受的连接请求。
      2. 当连接请求到达时,如果 尚未发布FD_ACCEPT
      3. 调用 接受 后,如果有另一个连接请求可供接受。
      4. FD_CONNECT
        1. WSAAsyncSelect 调用时,如果当前已建立连接。
        2. 调用 连接 后,建立连接 后, 即使连接立即成功,也与数据报套接字一样。
        3. 调用 WSAJoinLeaf 后,联接操作完成后。
        4. 连接后,使用非阻止、面向连接的套接字调用 WSAConnectWSAJoinLeaf。 初始操作返回时出现 WSAEWOULDBLOCK 的特定错误,但网络操作继续进行。 如果确定结果,操作最终是否成功, FD_CONNECT 发生。 客户端应检查错误代码,以确定结果是成功还是失败。
        5. FD_CLOSE:仅对面向连接的套接字有效 (,例如,SOCK_STREAM)
          1. WSAAsyncSelect 调用时,如果套接字连接已关闭。
          2. 远程系统启动正常关闭后,当当前没有数据可供接收 (请注意,如果已收到数据并在远程系统启动正常关闭时等待读取,则在读取所有挂起的数据) 之前, 不会 传送FD_CLOSE。
          3. 本地系统在关闭后正常 关闭 ,远程系统响应了“数据结束”通知 (,例如 TCP FIN) (当前没有可用的数据)。
          4. 例如,远程系统终止连接 (时,发送的 TCP RST) , lParam 将包含 WSAECONNRESET 错误值。
            请注意,在 调用 closesocket 后,不会发布FD_CLOSE。
          5. FD_GROUP_QOS:保留。
          6. FD_ROUTING_INTERFACE_CHANGE
            • 在调用SIO_ROUTING_INTERFACE_CHANGE WSAIoctl 后,应用于到达 IOCTL 中指定的目标的本地接口时。
            • FD_ADDRESS_LIST_CHANGE
              • 调用 SIO_ADDRESS_LIST_CHANGE WSAIoctl 后,应用程序可以绑定更改的本地地址列表。
  •