LPWSPASYNCSELECT 回调函数 (ws2spi.h)

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

语法

LPWSPASYNCSELECT Lpwspasyncselect;

int Lpwspasyncselect(
  [in]  SOCKET s,
  [in]  HWND hWnd,
  [in]  unsigned int wMsg,
  [in]  long lEvent,
  [out] LPINT lpErrno
)
{...}

参数

[in] s

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

[in] hWnd

处理标识在发生网络事件时应接收消息的窗口。

[in] wMsg

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

[in] lEvent

指定 Windows 套接字服务提供程序接口 (SPI) 客户端感兴趣的网络事件组合的位掩码。 通过使用这些值中的任何一个的按位 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
发出套接字协议系列的本地地址列表更改通知。

[out] lpErrno

指向错误代码的指针。 有关详细信息,请参阅 返回值 部分。

返回值

如果 Windows 套接字 SPI 客户端对网络事件集的兴趣声明成功,则返回值为零。 否则,将返回值 SOCKET_ERROR,并且 lpErrno 中提供了特定的错误代码。

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

有关应用程序窗口收到消息时可在消息) lParam 高字 (设置的其他错误代码的信息,请参阅备注

注解

此函数用于请求每当服务提供商检测到由 lEvent 参数指定的任何网络事件时,服务提供程序将 Windows 消息发送到客户端的窗口 hWnd。 服务提供商应使用 WPUPostMessage 函数发布消息。 要发送的消息由 wMsg 参数指定。 需要通知的套接字由 标识

无论 lEvent 的值如何,此函数都会自动将套接字 设置为非阻止模式。 请参阅 LPWSPIoctl ,了解如何将套接字设置回阻止模式。

调用套接字的 LPWSPAsyncSelect 将取消同一套接字的任何以前的 LPWSPAsyncSelectLPWSPEventSelect 。 例如,若要接收读取和写入通知,Windows 套接字 SPI 客户端必须使用FD_READ和FD_WRITE调用 LPWSPAsyncSelect ,如下所示。

rc = WSPAsyncSelect(s, hWnd, wMsg, FD_READ | FD_WRITE, &error);

无法为不同的事件指定不同的消息。 以下代码不起作用;第二个调用将取消第一个 的结果,唯一的关联将是与 wMsg2 关联的 FD_WRITE 事件。

// Incorrect example.
rc = WSPAsyncSelect(s, hWnd, wMsg1, FD_READ, &error);
rc = WSPAsyncSelect(s, hWnd, wMsg2, FD_WRITE, &error);

若要取消所有通知 (即,若要指示服务提供商不应再发送与套接字) 上的网络事件相关的消息,请将 lEvent 设置为零。

rc = WSPAsyncSelect(s, hWnd, 0, 0, &error);

由于 LPWSPAccept'ed 套接字与用于接受它的侦听套接字具有相同的属性,因此为侦听套接字设置的任何 LPWSPAsyncSelect 事件都适用于接受的套接字。 例如,如果侦听套接字具有 LPWSPAsyncSelect 事件FD_ACCEPT、FD_READ和FD_WRITE,则该侦听套接字上接受的任何套接字也将具有FD_ACCEPT、FD_READ和FD_WRITE事件,这些事件与消息使用的 wMsg 值相同。 如果需要不同的 wMsg 或事件,则 Windows 套接字 SPI 客户端应调用 LPWSPAsyncSelect,传递接受的套接字和所需的新信息。

当指定网络事件之一在 指定的套接字上发生时,服务提供商使用 WPUPostMessage 将消息 wMsg 发送到 Windows 套接字 SPI 客户端的窗口 hWnd。 在发布的消息中, wParam 参数标识发生了网络事件的套接字。 lParam 的低字指定已发生的网络事件。 可能指示的网络事件代码如下所示。

含义
FD_READ 套接字已准备好读取
FD_WRITE 套接字 已准备好写入
FD_OOB 带外数据已准备好在套接字 上读取
FD_ACCEPT 套接字 已准备好接受新的传入连接
FD_CONNECT 套接字 上 启动的连接已完成
FD_CLOSE 套接字 标识的连接已关闭
FD_QOS 套接字关联的 服务质量已更改
FD_GROUP_QOS 保留以供将来用于套接字组: 与套接字所属 的套接字组关联的服务质量已更改
FD_ROUTING_INTERFACE_CHANGE 应用于发送到指定目标的本地接口已更改
FD_ADDRESS_LIST_CHANGE Windows 套接字 SPI 客户端可以绑定到的套接字协议系列的地址列表已更改

lParam 的高字包含任何错误代码 (可以使用 WSAGETSELECTERROR 宏) 提取它。 错误代码是 中 ws2spi.h定义的任何错误。 下表列出了每个网络事件的可能错误代码。

事件:FD_CONNECT

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

事件:FD_CLOSE

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

事件...:FD_ACCEPT、FD_ADDRESS_LIST_CHANGE、FD_GROUP_QOS、FD_OOB、FD_QOS、FD_READ、FD_WRITE

错误代码 含义
WSAENETDOWN
网络子系统失败。

事件:FD_ROUTING_INTERFACE_CHANGE

错误代码 含义
WSAENETUNREACH
指定的目标不再可访问。
WSAENETDOWN
网络子系统失败。

尽管 LPWSPAsyncSelect 可以在多个事件中被调用,但服务提供商会为每个事件发出相同的 Windows 消息。

Windows 套接字 2 提供程序不应不断向 Windows 套接字 SPI 客户端填充特定网络事件的消息。 成功将特定事件的通知发布到 Windows 套接字 SPI 客户端窗口后,在 Windows 套接字 SPI 客户端进行函数调用以隐式重新启用该网络事件的通知之前,不会再向 Windows 套接字 SPI 客户端窗口发布任何消息 (该网络事件的) 。

网络事件 重新启用函数
FD_READ LPWSPRecvLPWSPRecvFrom
FD_WRITE LPWSPSendLPWSPSendTo
FD_OOB LPWSPRecvLPWSPRecvFrom
FD_ACCEPT LPWSPAccept,除非返回的错误代码WSATRY_AGAIN指示条件函数返回CF_DEFER
FD_CONNECT
FD_CLOSE
FD_QOS 带 SIO_GET_QOS 的 LPWSPIoctl
FD_GROUP_QOS 保留供套接字组将来使用: LPWSPIoctl 和 SIO_GET_GROUP_QOS
FD_ROUTING_INTERFACE_CHANGE 具有命令SIO_ROUTING_INTERFACE_CHANGE的 LPWSPIoctl
FD_ADDRESS_LIST_CHANGE 具有命令SIO_ADDRESS_LIST_CHANGE的 LPWSPIoctl

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

对于FD_READ、FD_OOB和FD_ACCEPT事件,消息发布是 级别触发的。 这意味着,如果调用重新启用例程,并且调用后仍满足相关条件,则会将 LPWSPAsyncSelect 消息发布到 Windows 套接字 SPI 客户端。

FD_QOS和FD_GROUP_QOS事件被视为 边缘触发的。 当发生 QOS 更改时,消息将恰好发布一次。 在提供程序检测到 QOS 的进一步更改,或者 Windows 套接字 SPI 客户端重新为套接字重新协商 QOS 之前,不会发出其他消息。

FD_ROUTING_INTERFACE_CHANGE和FD_ADDRESS_LIST_CHANGE事件也被视为 边缘触发 事件。 当 Windows 套接字 SPI 客户端通过发出 WSAIoctl 并相应地发出SIO_ROUTING_INTERFACE_CHANGE或SIO_ADDRESS_LIST_CHANGE来请求通知后发生更改时,消息将恰好发布一次。 在 Windows 套接字 SPI 客户端重新发出 IOCTL 并且 检测到自 IOCTL 发布以来的另一个更改之前,不会再收到其他消息。

如果 Windows 套接字 SPI 客户端调用 LPWSPAsyncSelect 或调用重新启用函数时已发生任何事件,则会根据需要发布消息。 例如,请考虑以下顺序。

  1. Windows 套接字 SPI 客户端调用 LPWSPListen
  2. 已收到连接请求,但尚未接受。
  3. Windows 套接字 SPI 客户端调用 LPWSPAsyncSelect ,指定它要接收套接字FD_ACCEPT消息。 由于事件的持久性,WinSock 服务提供商会立即发布FD_ACCEPT消息。

FD_WRITE 事件的处理方式略有不同。 当套接字在FD_CONNECT后首次与 LPWSPConnect (连接时,如果也注册) 或接受 LPWSPAccept,然后在 LPWSPSendLPWSPSend 失败并出现 WSAEWOULDBLOCK 且缓冲区空间变为可用之后,将发布FD_WRITE消息。 因此,Windows 套接字 SPI 客户端可以假定发送可能从第一个FD_WRITE消息开始,一直持续到发送返回 WSAEWOULDBLOCK。 发生此类故障后,Windows 套接字 SPI 客户端将收到通知,指出可以通过FD_WRITE消息再次发送。

仅当套接字配置为单独接收带外数据时,才使用 FD_OOB 事件。 如果套接字配置为接收带外数据内联,则带外 (加速) 数据被视为正常数据,并且 Windows 套接字 SPI 客户端必须注册对FD_READ事件的兴趣,而不是FD_OOB事件。

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

收到对应于套接字的虚拟线路的关闭指示时,将发布FD_CLOSE消息。 在 TCP 术语中,这意味着当连接进入 TIME WAIT 或 CLOSE WAIT 状态时,将发布FD_CLOSE。 这源于远程端在发送端或 LPWSPCloseSocket 上执行 LPWSPShutdown 只有在从套接字读取所有数据后,才发布FD_CLOSE是正确的。

在正常关闭的情况下,服务提供商应发送FD_CLOSE消息,以指示仅在读取所有接收的数据后虚拟线路关闭。 它不应发送FD_READ消息来指示此条件。

当流规范中与套接字 关联的任何字段发生更改时,将分别发布FD_QOS或FD_GROUP_QOS消息。 服务提供商必须使用 SIO_GET_QOS 和/或SIO_GET_GROUP_QOS更新通过 LPWSPIoctl 提供给客户端的 QOS 信息。

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

FD_ADDRESS_LIST_CHANGE消息在发出 LPWSPIoctl 和 SIO_ADDRESS_LIST_CHANGE ,Windows 套接字 SPI 客户端可以将更改绑定到的地址列表时发布。

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

FD_READ

  1. 调用 LPWSPAsyncSelect 时,如果当前有数据可供接收,
  2. 数据到达时,如果FD_READ尚未发布。
  3. 调用 LPWSPRecvLPWSPRecvFrom 后,如果数据仍可供接收,则 (无论是否MSG_PEEK) 。

启用 LPWSPSetSockOpt SO_OOBINLINE后, 数据 包括正常数据和带外数据 (OOB) 上述实例中的数据。

FD_WRITE

  1. 调用 LPWSPAsyncSelect 时,如果 LPWSPSendLPWSPSendTo 是可能的。
  2. 在建立连接时调用 LPWSPConnectLPWSPAccept 之后。
  3. 当 LPWSPSendLPWSPSendTo 失败并出现 WSAEWOULDBLOCK 后,LPWSPSendLPWSPSendTo 可能会成功。
  4. 在无连接套接字上 LPWSPBind 之后。 FD_WRITE (依赖于实现的) ,此时可能会发生,也可能不发生。 在任何情况下,无连接套接字始终在 LPWSPBind 之后立即可写。

当禁用 LPWSPSetSockOpt SO_OOBINLINE (默认) ) 时,FD_OOB (有效

  1. 调用 LPWSPAsyncSelect 时,如果当前有可以使用 MSG_OOB 标志接收的 OOB 数据。
  2. 当 OOB 数据到达时,如果FD_OOB尚未发布。
  3. 使用或不带MSG_OOB标志调用 LPWSPRecvLPWSPRecvFrom 后,如果 OOB 数据仍可供接收,

FD_ACCEPT

  1. 调用 LPWSPAsyncSelect 时,如果当前存在可接受的连接请求。
  2. 当连接请求到达时,如果FD_ACCEPT尚未发布。
  3. 调用 LPWSPAccept 后,如果有另一个连接请求可供接受。

FD_CONNECT

  1. 调用 LPWSPAsyncSelect 时,如果当前已建立连接,
  2. 调用 LPWSPConnect 后,建立连接时 (即使 LPWSPConnect 立即成功,数据报套接字) 通常也是如此,即使它立即) 失败也是如此。
  3. 调用 WSPJoinLeaf 后,联接操作完成时。
  4. 连接后,WSAConnectWSPJoinLeaf 是使用非阻塞的面向连接的套接字调用的。 初始操作返回并显示 WSAEWOULDBLOCK 的特定错误,但网络操作继续进行。 无论操作最终是否成功,在确定结果后,FD_CONNECT发生。 客户端应检查错误代码,以确定结果是成功还是失败。

FD_CLOSE (仅在面向连接的套接字 (有效,例如,SOCK_STREAM) )

  1. 调用 LPWSPAsyncSelect 时,如果套接字连接已关闭。
  2. 在远程系统启动正常关闭后,如果当前没有数据可用于接收 (如果已收到数据,并且正在等待在远程系统启动正常关闭时读取,则在读取所有挂起的数据) 之前,不会传递FD_CLOSE。
  3. 在本地系统使用 LPWSPShutdown 启动正常关闭后,当当前没有数据可供接收时,远程系统已使用 数据结束 通知 ((例如 TCP FIN) )做出响应。
  4. 例如,远程系统中止连接 (发送的 TCP RST ) ,lParam 将包含 WSAECONNRESET 错误值。

调用 LPWSPCloseSocket 后,不会发布FD_CLOSE。

FD_QOS

  1. 调用 LPWSPAsyncSelect 时,如果已更改与套接字关联的 QOS。
  2. 调用具有 SIO_GET_QOS的 LPWSPIoctl 后,当 QOS 发生更改时。

FD_GROUP_QOS

保留以供将来使用套接字组:

  1. 调用 LPWSPAsyncSelect 时,如果已更改与套接字关联的组 QOS。
  2. 调用具有 SIO_GET_GROUP_QOS的 LPWSPIoctl 后,当组 QOS 发生更改时。

FD_ROUTING_INTERFACE_CHANGE

  1. 使用 SIO_ROUTING_INTERFACE_CHANGE 调用 LPWSPIoctl 之后,应用于访问 IOCTL 中指定的目标的本地接口发生更改。

FD_ADDRESS_LIST_CHANGE

  1. LPWSPIoctl 和 SIO_ADDRESS_LIST_CHANGE 调用后,当 Windows 套接字 SPI 客户端可以绑定到的本地地址列表发生更改时。

要求

要求
最低受支持的客户端 Windows 10内部版本 20348
最低受支持的服务器 Windows 10内部版本 20348
标头 ws2spi.h

另请参阅

LPWSPAsyncSelect 回调函数