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

And*_*nga 12 .net c# sockets

我正在做一些测试试图隔离库中的一些奇怪的行为(.NET).当我通过C++使用Winsock API并简单地调用closesocket()时,我看到windows端发送FIN/ACK数据包,远程端发回ACK数据包.这就是我称之为优雅的结果.但是,当用C#编程时,我没有看到我称之为优雅的结果.

在C#中,我打开我的套接字然后,当关闭它时,我看到Windows发送FIN数据包只有在第一次调用Socket.Shutdown()时.但是,无论如何,当我在C#中调用Socket.Close()时,会发送一个RST数据包并立即删除连接.这让我感到困惑,因为从我在线阅读的内容来看,TCP关闭过程应该是FIN/ACK - > ACK(实际上来自双方,但是现在,我只关心"我的"方面); 即,混合中根本不应该有RST数据包.从我所看到的,显然,只有当接收器不确定连接状态并且想要输出时才发送RST数据包.

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

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

Bok*_*ius 5

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

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

这实际上是有道理的。如果缓冲区(操作系统之一)中仍有数据,并且您断开了连接或终止了该进程,则连接将被重置(TCP规范中的更多详细信息)。

至于何时发送RST,请查阅《TCP Guide》

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


And*_*mar 0

最近遇到了一个类似的问题,应用程序正在与 Exchange 服务器进行 POP3 通信。当 .NET 程序完成时,它不正常地关闭,并且 Exchange 将 POP3 会话视为“已中止”并将其回滚。

原因是我认为 TCP RST 是一个“单向”消息——您不必等待回复。这就是 .NET 发送的内容(或者可能是终止后的任何程序)。一种可能的解决方案是在关闭套接字之后和退出程序之前等待一段时间:

Thread.Sleep(5000);
Run Code Online (Sandbox Code Playgroud)

这对我之前提到的 POP3 问题有效;等待时间导致连接正常关闭,并且 Exchange 不再中止会话。