#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
recv、 recvfrom、 WSARecv 或 WSARecvFrom。
FD_WRITE
send、sendto、WSASend 或 WSASendTo。
FD_OOB
recv、 recvfrom、 WSARecv 或 WSARecvFrom。
FD_ACCEPT
接受 或 WSAAccept ,除非错误代码 WSATRY_AGAIN 指示条件函数返回CF_DEFER。
FD_CONNECT
FD_CLOSE
FD_QOS
具有命令SIO_GET_QOS的 WSAIoctl。
FD_GROUP_QOS
使用命令SIO_GET_GROUP_QOS (保留 WSAIoctl,以便将来与套接字组一起使用) 。
FD_ROUTING_INTERFACE_CHANGE
具有命令SIO_ROUTING_INTERFACE_CHANGE的 WSAIoctl。
FD_ADDRESS_LIST_CHANGE
具有命令SIO_ADDRESS_LIST_CHANGE的 WSAIoctl。
对重新调用例程(即使是失败例程)的任何调用都会导致重新调用相关事件的消息发布。
对于 FD_READ、 FD_OOB和 FD_ACCEPT 事件,消息发布是级别触发的。 这意味着,如果调用重新调用例程,并且调用后仍满足相关条件,则会向应用程序发布 WSAAsyncSelect 消息。 这样,应用程序就可以由事件驱动,并且不关心任何一次到达的数据量。 考虑以下序列:
网络传输堆栈 在套接字上 接收 100 字节的数据,并导致 Windows 套接字 2 发布 FD_READ 消息。
应用程序发出 recv ( s、 buffptr、50, 0) 读取 50 字节。
发布另一 条FD_READ 消息,因为仍有要读取的数据。
借助这些语义,应用程序不需要读取所有可用数据以响应 FD_READ 消息-单个 recv 以响应每个 FD_READ 消息是合适的。 如果应用程序在响应单个FD_READ时发出多个 recv 调用,则它可以接收多个FD_READ消息。 此类应用程序可能需要禁用FD_READ消息,然后才能通过未设置FD_READ事件调用 WSAAsyncSelect 来启动 recv 调用。
FD_QOS和FD_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 事件。 应用程序可以使用 setockopt 或 getsockopt 为 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_QOS或FD_GROUP_QOS消息。 应用程序应将 WSAIoctl 与命令SIO_GET_QOS或SIO_GET_GROUP_QOS结合使用,以便分别获取套接字 组 或 套接字组所属 的当前服务质量。
FD_ROUTING_INTERFACE_CHANGE和FD_ADDRESS_LIST_CHANGE事件也被视为触发边缘。 当应用程序请求通知通知后,应用程序发出SIO_ROUTING_INTERFACE_CHANGE或相应SIO_ADDRESS_LIST_CHANGE 来发出通知 后,将恰好发布一次消息。 在应用程序重新发出 IOCTL 并检测到另一个更改之前,才会发出进一步消息,因为 IOCTL 已发出。
下面是每个异步通知消息的事件和条件的摘要。
FD_READ:
- 调用 WSAAsyncSelect 时,如果有数据当前可用于接收。
- 数据到达时,如果 尚未发布FD_READ 。
- 调用 recv 或 recvfrom 后,如果数据仍可供接收,则使用或不使用MSG_PEEK) 。
注意 启用
setsockopt SO_OOBINLINE 后,数据在上面记录的实例中包含普通数据和 OOB 数据。
- 当 WSAAsyncSelect 调用时,如果有可能 发送 或 sendto 。
- 连接或接受调用后,建立连接时。
- 发送或 sendto 失败且 WSAEWOULDBLOCK 失败后,发送或 sendto 可能会成功。
- 在无连接套接字上 绑定 后。 FD_WRITE 目前可能或可能不会发生 (依赖实现的) 。 在任何情况下,在 绑定 操作后,无连接套接字始终可立即写入。
- FD_OOB:仅在默认) (禁用 setsockopt SO_OOBINLINE时才有效。
- 当 WSAAsyncSelect 调用时,如果有 OOB 数据当前可用于接收MSG_OOB标志。
- 当 OOB 数据到达时,如果 尚未发布FD_OOB 。
- 使用或不带MSG_OOB标志调用 recv 或 recvfrom 后,如果 OOB 数据仍可供接收。
- FD_ACCEPT:
- 当 WSAAsyncSelect 调用时,如果当前有一个可供接受的连接请求。
- 当连接请求到达时,如果 尚未发布FD_ACCEPT 。
- 调用 接受 后,如果有另一个连接请求可供接受。
- FD_CONNECT:
- 当 WSAAsyncSelect 调用时,如果当前已建立连接。
- 调用 连接 后,建立连接 后, 即使连接立即成功,也与数据报套接字一样。
- 调用 WSAJoinLeaf 后,联接操作完成后。
- 连接后,使用非阻止、面向连接的套接字调用 WSAConnect 或 WSAJoinLeaf。 初始操作返回时出现 WSAEWOULDBLOCK 的特定错误,但网络操作继续进行。 如果确定结果,操作最终是否成功, FD_CONNECT 发生。 客户端应检查错误代码,以确定结果是成功还是失败。
- FD_CLOSE:仅对面向连接的套接字有效 (,例如,SOCK_STREAM)
- 当 WSAAsyncSelect 调用时,如果套接字连接已关闭。
- 远程系统启动正常关闭后,当当前没有数据可供接收 (请注意,如果已收到数据并在远程系统启动正常关闭时等待读取,则在读取所有挂起的数据) 之前, 不会 传送FD_CLOSE。
- 本地系统在关闭后正常 关闭 ,远程系统响应了“数据结束”通知 (,例如 TCP FIN) (当前没有可用的数据)。
- 例如,远程系统终止连接 (时,发送的 TCP RST) , lParam 将包含 WSAECONNRESET 错误值。
- FD_GROUP_QOS:保留。
- FD_ROUTING_INTERFACE_CHANGE:
- 在调用SIO_ROUTING_INTERFACE_CHANGE WSAIoctl 后,应用于到达 IOCTL 中指定的目标的本地接口时。
- FD_ADDRESS_LIST_CHANGE:
- 调用 SIO_ADDRESS_LIST_CHANGE WSAIoctl 后,应用程序可以绑定更改的本地地址列表。