如何防止.NET库在关闭时发送RST数据包

时间:2011-08-23 17:00:47

标签: c# .net sockets

我正在做一些测试,尝试隔离库中的一些奇怪的行为(.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()方法之前读取套接字上的所有可用数据。

4 个答案:

答案 0 :(得分:5)

阅读Socket.Close的.NET文档,这是我发现的:

  

对于面向连接的协议,建议您拨打电话   在调用Close方法之前关闭。这确保了所有数据   在连接的套接字关闭之前发送和接收。如果   你需要在没有先打电话给Shutdown的情况下拨打关闭,你可以确保   排队等待传出传输的数据将通过设置发送   DontLinger套接字选项为false并指定非零超时   间隔。然后关闭将阻止,直到发送此数据或直到该数据   指定的超时到期。如果将DontLinger设置为false并指定   零超时间隔,关闭释放连接和   自动丢弃传出的排队数据。

这实际上是有道理的。如果缓冲区中存在静态数据(OS一)并且您断开连接或终止连接,则将重置连接(TCP规范中的更详细信息)。

关于何时发送RST,请查看TCP Guide

我的猜测是仍有一些未设置或正在传输的数据或传出/进入缓冲区触发RST。

答案 1 :(得分:2)

以下代码可能会阻止RST数据包。这是因为在发送FIN数据包后等待60秒。

socket.Close(60);

关闭方法说明为here

答案 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。