我该如何完全关闭与MCU的tcpClient连接?

8

我现在正在处理与运行在ESP32上的tcp服务器的tcp套接字连接。 通信方面没有问题,但是我无法关闭这个连接。 在搜索了解如何关闭/重置tcp客户端的解决方案后,似乎正确的关闭tcp客户端的方法应该是:

tcpClient.GetStream().Close();
tcpCLient.Close();

这篇在 MSDN 上的示例 也使用了这种方法。

但不幸的是,它并不能真正关闭连接。在 MCU 中检查时,发现连接并未关闭。即使稍后我关闭应用程序,它也不会关闭。在这种情况下,MCU 的 TCP 连接无法释放,也无法接受其他连接。因此,我认为这不是一个正确的关闭 tcpClient 的解决方案。

如果我没有执行上述语句,直接关闭应用程序,则可以成功关闭连接。MCU 的 TCP 连接也将被释放。

似乎在关闭应用程序时进行了一些操作,可以真正地关闭连接。

在某些情况下,我需要在某些操作后关闭连接,并重新连接。因此,我不能依赖于应用程序的关闭。

我尝试了以下所有方法的不同组合,但它们都不能成功释放 tcpClient 连接:

 tcpClient.Close(); 
 tcpClient.Client.Close();
 tcpClient.GetStream().Close();
 tcpClient.Client.Disconnect(true);
 tcpClient.Client.Disconnect(false);
 tcpClient.Dispose();
 tcpClient.Client.Dispose();
 tcpCLient = null;

也许应该按照正确的顺序使用上述一些命令来完成。

有没有人知道我如何自己关闭连接。

提前致谢。

2个回答

5
使用WireShark分析网络数据包后,发现问题是由于发送RST代码时出现延迟,正如MSDN所建议的那样。
tcpClient.GetStream().Close();
tcpCLient.Close();

即使添加了也没有任何不同

tcpClient.LingerState = new LingerOptions(true, 0);

由于Close方法会立即发送FIN,但不是发送RST,因此FIN将在大约2分钟后发送。不幸的是,即使在发出tcpClient close命令后关闭应用程序,它也不会被发送。

enter image description here

如果在关闭tcpClient之前关闭应用程序,它将立即发送RST。

enter image description here

为了让服务器能够立即关闭连接。

经过测试不同的命令组合,发现以下代码确实可以立即关闭连接,但大约40秒后会有另一个RST。

tcpClient.Client.Close();
tcpClient.Close();

enter image description here

不要调用tcpClient.GetStream().Close(); !!! 这会导致RST的延迟。

我不知道以这种方式关闭连接是否会有任何影响,但这是我唯一能够立即关闭连接的方法。


感谢更好的示例。所有的连接重置正确,就像关闭应用程序一样。 - Rootware

0

正如你所提到的,这是关闭 TcpClient 的正确方式:

tcpClient.GetStream().Close();
tcpCLient.Close();

Close() 方法最终会关闭连接。请查看 TcpClient.Close() 的文档。

Close 方法将实例标记为已处理并请求关联的 Socket 关闭 TCP 连接。根据 LingerState 属性,当仍有数据需要发送时,在调用 Close 方法后,TCP 连接可能会保持打开状态一段时间。在底层连接完成关闭时不提供任何通知。

通过更改 TcpClient 对象的 LingerState 属性,您可以获得所需的行为。

linger state options

tcpClient.LingerState = new LingerOptions(true, 0);

不,即使添加了LingerState选项,它也无法关闭连接。首先,服务器端没有关闭,即使我重新启动服务器,客户端也无法重新连接服务器。这与关闭应用程序不同,关闭应用程序可以向服务器端确认连接已关闭,并且可以接收其他连接。 - James MA
仅供参考,如果我再次尝试连接服务器(甚至重新启动服务器并尝试重新连接),将会出现以下异常信息:"在已连接的套接字上尝试了一个连接请求"。 - James MA
另一个更新,如果我调用tcpClient.client.close()而不是tcpCient.close(),则会抛出上述异常。如果我调用tcpClient.close(),它将销毁tcpClient对象,并且无法使用。但是,在服务器端,连接仍未关闭,因此即使稍后创建新的tcpClient,也无法连接服务器。 - James MA
刚刚使用 WireShark 进行了检查,发现那些 close 命令不会向服务器发送 RST,因此连接并没有真正关闭,它会在大约 2 分钟后发送 RST。但是如果在调用 tcpClient close 前关闭应用程序,则会立即发送 RST。因此,关闭应用程序可以立即断开连接,而 close 命令则不能。有没有办法直接发送 RST? - James MA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接