2011-08-23 75 views
9

我正在做一些测试,试图隔离库(.NET)中的一些奇怪行为。当我通过C++使用Winsock API并简单地调用closesocket()时,我发现窗口端发送FIN/ACK数据包,远端发送一个ACK数据包。这就是我所称的优雅结尾。但是,当用C#编程时,我没有看到我会称之为优雅的关闭。在C#中,我打开我的套接字,然后在关闭它时,我看到windows首先调用Socket.Shutdown()时发送一个FIN数据包只有。但是,无论如何,当我在C#中调用Socket.Close()时,都会发送一个RST数据包,并且连接立即被丢弃。这让我感到困惑,因为从我在线阅读的内容来看,TCP关闭过程应该是FIN/ACK - > ACK(实际上双方都是,但现在我只关心“我的”方面);即根本不应该有混合中的RST分组。从我读过的内容来看,显然,只有当接收者对连接状态不确定并且想要出去时才会发送RST数据包。如何防止.NET库关闭发送RST数据包

为什么这个RST数据包是在.NET中按计划关机发送的,而根本没有在从winsock API计划关机时发送?有没有办法阻止从.NET正常关机期间传输RST数据包?

如果重要,在两个代码路径中,我在调用相应的close()方法之前先读取套接字上的所有可用数据。

回答

0

刚刚遇到类似的问题,其中应用程序正在向POP3服务器通话POP3。当.NET程序完成时,它非正式关闭,Exchange将POP3对话视为“中止”并将其回滚。

原因是我认为TCP RST是一个“单向”消息 - 你不必等待回复。所以这是.NET发送的内容(或者也许是终止后的任何程序),一个可行的办法是关闭套接字后退出程序之前等待了一下:

Thread.Sleep(5000); 

这个工作对我前面提到的POP3问题;等待时间导致连接正常关闭,Exchange不再中止会话。

+1

这很有趣。我必须看到当我实施睡眠时会发生什么。我不知道还会出现什么,因为我不认为这是可行的(如果它的作品)在这种情况发生的全部背景。我制作了框架程序来隔离行为。不过谢谢你,因为我没有想过在这里使用睡眠电话。 –

3

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

对于面向连接的协议,建议您调用Close方法之前调用 关机。这确保所有数据 在关闭之前在连接的套接字上发送和接收。如果 需要在没有首先调用Shutdown的情况下调用Close,则可以确保 通过将 DontLinger套接字选项设置为false并指定非零超时 时间间隔来发送排队等待传出传输的数据。关闭将会阻塞,直到这个数据被发送,或者直到 指定的超时时间到期。如果将DontLinger设置为false,并指定 零超时间隔,则关闭释放连接并自动丢弃传出排队数据。

这实际上是有意义的。如果缓冲区中存在数据(操作系统一),并且断开连接或终止进程,连接将被重置(TCP规范中的更详细信息)。

至于何时发送RST退房TCP Guide

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

1

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

socket.Close(60); 

关闭方法描述是here