当连接建立时,远端会发送一个设置了SYN标志的数据包。服务器回复SYN,ACK包,然后远端发送ACK包,其中可能已经包含数据。
有两种方法可以中断 TCP 连接的形成。第一个是重置连接——这与连接到无人监听的端口时常见的“连接被拒绝”消息相同。在这种情况下,原始的 SYN 数据包会得到一个 RST 数据包的响应,该数据包会立即终止连接并且是无状态的。如果 SYN 被重新发送,RST 将从每个收到的 SYN 数据包中生成。
第二个是在连接形成后立即关闭。在 TCP 级别上,无法立即关闭双向连接 - 你唯一能说的是“我不会再发送任何数据”。发生这种情况时,当初始 SYN、SYN,ACK、ACK 交换完成时,服务器会发送 FIN 数据包到远端。在大多数情况下,用 FIN 告诉另一端“我不会再发送任何数据”会使另一端也关闭连接,并发送它自己的 FIN 数据包。以这种方式终止的连接与由于某种原因没有发送数据的正常连接没有任何不同。这意味着 TCP 连接的正常状态跟踪和延迟关闭状态将持续存在,就像正常连接一样。
现在,在 C API 方面,这看起来有点不同。在端口上调用listen() 时,操作系统开始接受该端口上的连接。这意味着它开始向连接回复 SYN,ACK 数据包,无论 C 代码是否已调用 accept()。因此,在 TCP 方面,无论是在接受之前还是之后以某种方式关闭连接都没有区别。唯一额外的问题是侦听套接字有积压,这意味着它可以等待的未接受连接的数量,然后才开始对远程端说 RST。
但是,在 Windows 上,SO_CONDITIONAL_ACCEPT 调用允许应用程序控制积压队列。这意味着服务器不会对 SYN 数据包回答 anything,直到应用程序对连接进行某些操作。这意味着,在这个级别拒绝连接实际上可以在不创建状态的情况下向网络发送 RST 数据包。
因此,如果您无法以某种方式在您使用AcceptEx 的套接字上启用SO_CONDITIONAL_ACCEPT 功能,则它将以不同的方式显示给网络。然而,真正使用即时 RST 功能的地方并不多,所以我认为对此的要求确实意味着一个非常专业的系统。对于最常见的用例,接受一个套接字然后关闭它是正常的行为方式。