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 运算符构造。
值 | 含义 |
---|---|
|
发出阅读就绪通知。 |
|
发出准备写入通知。 |
|
发出 OOB 数据到达的通知。 |
|
发出传入连接的通知。 |
|
发出已完成连接的通知。 |
|
发出套接字关闭通知。 |
|
发出套接字服务质量 (QoS) 更改的通知。 |
|
保留。 |
|
发出指定目标的路由接口更改通知。 |
|
发出套接字协议系列的本地地址列表更改通知。 |
[out] lpErrno
指向错误代码的指针。 有关详细信息,请参阅 返回值 部分。
返回值
如果 Windows 套接字 SPI 客户端对网络事件集的兴趣声明成功,则返回值为零。 否则,将返回值 SOCKET_ERROR,并且 lpErrno 中提供了特定的错误代码。
错误代码 | 含义 |
---|---|
网络子系统失败。 | |
指示指定参数之一无效,例如窗口句柄未引用现有窗口,或者指定的套接字处于无效状态。 | |
阻止 Windows 套接字调用正在进行,或者服务提供商仍在处理回调函数。 | |
:描述符不是套接字。 |
有关应用程序窗口收到消息时可在消息) lParam 高字 (设置的其他错误代码的信息,请参阅备注。
注解
此函数用于请求每当服务提供商检测到由 lEvent 参数指定的任何网络事件时,服务提供程序将 Windows 消息发送到客户端的窗口 hWnd。 服务提供商应使用 WPUPostMessage 函数发布消息。 要发送的消息由 wMsg 参数指定。 需要通知的套接字由 标识。
无论 lEvent 的值如何,此函数都会自动将套接字 设置为非阻止模式。 请参阅 LPWSPIoctl ,了解如何将套接字设置回阻止模式。
调用套接字的 LPWSPAsyncSelect 将取消同一套接字的任何以前的 LPWSPAsyncSelect 或 LPWSPEventSelect 。 例如,若要接收读取和写入通知,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
错误代码 | 含义 |
---|---|
指定系列中的地址无法与此套接字一起使用。 | |
:连接尝试被拒绝。 | |
此时不可以从此主机访问该网络。 | |
namelen 参数无效。 | |
:套接字已绑定到地址。 | |
:套接字已连接。 | |
没有更多可用的文件描述符。 | |
未提供任何缓冲区空间。 无法连接套接字。 | |
套接字未连接。 | |
:连接尝试超时,没有建立连接。 |
事件:FD_CLOSE
错误代码 | 含义 |
---|---|
网络子系统失败。 | |
:此连接已由远端重置。 | |
由于超时或其他故障,连接已终止。 |
事件...:FD_ACCEPT、FD_ADDRESS_LIST_CHANGE、FD_GROUP_QOS、FD_OOB、FD_QOS、FD_READ、FD_WRITE
错误代码 | 含义 |
---|---|
网络子系统失败。 |
事件:FD_ROUTING_INTERFACE_CHANGE
错误代码 | 含义 |
---|---|
指定的目标不再可访问。 | |
网络子系统失败。 |
尽管 LPWSPAsyncSelect 可以在多个事件中被调用,但服务提供商会为每个事件发出相同的 Windows 消息。
Windows 套接字 2 提供程序不应不断向 Windows 套接字 SPI 客户端填充特定网络事件的消息。 成功将特定事件的通知发布到 Windows 套接字 SPI 客户端窗口后,在 Windows 套接字 SPI 客户端进行函数调用以隐式重新启用该网络事件的通知之前,不会再向 Windows 套接字 SPI 客户端窗口发布任何消息 (该网络事件的) 。
网络事件 | 重新启用函数 |
---|---|
FD_READ | LPWSPRecv 或 LPWSPRecvFrom |
FD_WRITE | LPWSPSend 或 LPWSPSendTo |
FD_OOB | LPWSPRecv 或 LPWSPRecvFrom |
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 或调用重新启用函数时已发生任何事件,则会根据需要发布消息。 例如,请考虑以下顺序。
- Windows 套接字 SPI 客户端调用 LPWSPListen。
- 已收到连接请求,但尚未接受。
- Windows 套接字 SPI 客户端调用 LPWSPAsyncSelect ,指定它要接收套接字FD_ACCEPT消息。 由于事件的持久性,WinSock 服务提供商会立即发布FD_ACCEPT消息。
FD_WRITE 事件的处理方式略有不同。 当套接字在FD_CONNECT后首次与 LPWSPConnect (连接时,如果也注册) 或接受 LPWSPAccept,然后在 LPWSPSend 或 LPWSPSend 失败并出现 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
- 调用 LPWSPAsyncSelect 时,如果当前有数据可供接收,
- 数据到达时,如果FD_READ尚未发布。
- 调用 LPWSPRecv 或 LPWSPRecvFrom 后,如果数据仍可供接收,则 (无论是否MSG_PEEK) 。
启用 LPWSPSetSockOpt SO_OOBINLINE后, 数据 包括正常数据和带外数据 (OOB) 上述实例中的数据。
FD_WRITE
- 调用 LPWSPAsyncSelect 时,如果 LPWSPSend 或 LPWSPSendTo 是可能的。
- 在建立连接时调用 LPWSPConnect 或 LPWSPAccept 之后。
- 当 LPWSPSend 或 LPWSPSendTo 失败并出现 WSAEWOULDBLOCK 后,LPWSPSend 或 LPWSPSendTo 可能会成功。
- 在无连接套接字上 LPWSPBind 之后。 FD_WRITE (依赖于实现的) ,此时可能会发生,也可能不发生。 在任何情况下,无连接套接字始终在 LPWSPBind 之后立即可写。
仅 当禁用 LPWSPSetSockOpt SO_OOBINLINE (默认) ) 时,FD_OOB (有效
- 调用 LPWSPAsyncSelect 时,如果当前有可以使用 MSG_OOB 标志接收的 OOB 数据。
- 当 OOB 数据到达时,如果FD_OOB尚未发布。
- 使用或不带MSG_OOB标志调用 LPWSPRecv 或 LPWSPRecvFrom 后,如果 OOB 数据仍可供接收,
FD_ACCEPT
- 调用 LPWSPAsyncSelect 时,如果当前存在可接受的连接请求。
- 当连接请求到达时,如果FD_ACCEPT尚未发布。
- 调用 LPWSPAccept 后,如果有另一个连接请求可供接受。
FD_CONNECT
- 调用 LPWSPAsyncSelect 时,如果当前已建立连接,
- 调用 LPWSPConnect 后,建立连接时 (即使 LPWSPConnect 立即成功,数据报套接字) 通常也是如此,即使它立即) 失败也是如此。
- 调用 WSPJoinLeaf 后,联接操作完成时。
- 连接后,WSAConnect 或 WSPJoinLeaf 是使用非阻塞的面向连接的套接字调用的。 初始操作返回并显示 WSAEWOULDBLOCK 的特定错误,但网络操作继续进行。 无论操作最终是否成功,在确定结果后,FD_CONNECT发生。 客户端应检查错误代码,以确定结果是成功还是失败。
FD_CLOSE (仅在面向连接的套接字 (有效,例如,SOCK_STREAM) )
- 调用 LPWSPAsyncSelect 时,如果套接字连接已关闭。
- 在远程系统启动正常关闭后,如果当前没有数据可用于接收 (如果已收到数据,并且正在等待在远程系统启动正常关闭时读取,则在读取所有挂起的数据) 之前,不会传递FD_CLOSE。
- 在本地系统使用 LPWSPShutdown 启动正常关闭后,当当前没有数据可供接收时,远程系统已使用 数据结束 通知 ((例如 TCP FIN) )做出响应。
- 例如,远程系统中止连接 (发送的 TCP RST ) ,lParam 将包含 WSAECONNRESET 错误值。
调用 LPWSPCloseSocket 后,不会发布FD_CLOSE。
FD_QOS
- 调用 LPWSPAsyncSelect 时,如果已更改与套接字关联的 QOS。
- 调用具有 SIO_GET_QOS的 LPWSPIoctl 后,当 QOS 发生更改时。
FD_GROUP_QOS
保留以供将来使用套接字组:
- 调用 LPWSPAsyncSelect 时,如果已更改与套接字关联的组 QOS。
- 调用具有 SIO_GET_GROUP_QOS的 LPWSPIoctl 后,当组 QOS 发生更改时。
FD_ROUTING_INTERFACE_CHANGE
- 使用 SIO_ROUTING_INTERFACE_CHANGE 调用 LPWSPIoctl 之后,应用于访问 IOCTL 中指定的目标的本地接口发生更改。
FD_ADDRESS_LIST_CHANGE
- 在 LPWSPIoctl 和 SIO_ADDRESS_LIST_CHANGE 调用后,当 Windows 套接字 SPI 客户端可以绑定到的本地地址列表发生更改时。
要求
要求 | 值 |
---|---|
最低受支持的客户端 | Windows 10内部版本 20348 |
最低受支持的服务器 | Windows 10内部版本 20348 |
标头 | ws2spi.h |
另请参阅
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈