我正在做一些测试,尝试隔离库中的一些奇怪的行为(.NET)。当我通过C ++使用Winsock API并简单地调用closesocket()
时,我看到窗口侧发送FIN / ACK数据包,远程端发送回ACK数据包。这就是我称之为优雅的结果。然而,当用C#编程时,我没有看到我称之为优雅的关闭。
在C#中,我打开我的套接字,然后在关闭它时,我看到Windows在第一次调用Socket.Shutdown()
时发送一个FIN数据包仅。但是,无论如何,当我在C#中调用Socket.Close()
时,会发送一个RST数据包并立即删除连接。这让我感到困惑,因为从我在线阅读的内容来看,TCP关闭过程应该是FIN / ACK - >确认(实际上来自双方,但现在,我只关心“我的”方面);即根本不应该在混合中存在RST分组。从我所看到的,显然,只有当接收者不确定连接状态并想要发送RST数据包时才会发送。
为什么这个RST数据包是在.NET中的计划关闭时发送的,而不是在winsock API的计划关闭中发送的?有没有办法阻止在从.NET正常关闭期间传输RST数据包?
如果重要的话,在两个代码路径中,我都会在调用相应的close()
方法之前读取套接字上的所有可用数据。
答案 0 :(得分:5)
阅读Socket.Close的.NET文档,这是我发现的:
对于面向连接的协议,建议您拨打电话 在调用Close方法之前关闭。这确保了所有数据 在连接的套接字关闭之前发送和接收。如果 你需要在没有先打电话给Shutdown的情况下拨打关闭,你可以确保 排队等待传出传输的数据将通过设置发送 DontLinger套接字选项为false并指定非零超时 间隔。然后关闭将阻止,直到发送此数据或直到该数据 指定的超时到期。如果将DontLinger设置为false并指定 零超时间隔,关闭释放连接和 自动丢弃传出的排队数据。
这实际上是有道理的。如果缓冲区中存在静态数据(OS一)并且您断开连接或终止连接,则将重置连接(TCP规范中的更详细信息)。
关于何时发送RST,请查看TCP Guide。
我的猜测是仍有一些未设置或正在传输的数据或传出/进入缓冲区触发RST。
答案 1 :(得分:2)
答案 2 :(得分:0)
就在最近遇到类似的问题,应用程序正在将POP3与Exchange Server进行通信。当.NET程序完成时,它以非正常方式关闭,并且Exchange将POP3对话视为“已中止”并将其回滚。
原因是我认为TCP RST是一种“单向”消息 - 您不必等待回复。这就是.NET发送的内容(或者它终止之后的任何程序)。一种可能的解决方案是在关闭套接字后退出程序之前稍等一下:
Thread.Sleep(5000);
这适用于我前面提到的POP3问题;等待时间导致连接正常关闭,Exchange不再中止会话。
答案 3 :(得分:0)
在类似情况下,我打电话给socket.Disconnect(false)
而不是socket.Close()
。
if (theSenderSocket != null){
theSenderSocket.Disconnect(false);
}
然后检查Wireshark筛选器,发现如果是RST / ACK,它发送的是FIN / ACK。