检查 TcpClient 是否实际连接

Checking a TcpClient is actually connected

与许多人一样,我一直在研究测试 TCP 会话是否 active/alive 的主题。太多半有效的解决方案似乎是一个不必要的难题。连接在测试自身之前什么都不知道。然后尝试发送可能会成功,尽管连接实际上已经丢失。轮询似乎为连接提供了误报。某些服务器配置为不响应 ping。唯一真正的考验似乎是尝试建立新的联系并判断尝试是否成功。这似乎是不必要的严厉,但该协议没有一种轻量级的方式来回答 'in this particular instant, is it possible to transfer data from client to server and verify that it was received?'

的问题,这似乎很疯狂

我正在使用 .net 框架和其中公开的 TCP 对象。当断开网络电缆时,这肯定会立即向所有消费者发出连接断开的信号。然而,情况并非如此,我对连接的任何感觉都没有意识到这种损失。只有尝试重新建立连接才发现物理 link 已经断开。

我错过了什么?

TCP 并不像您认为的那样真正工作,尽管我们可以做一些事情让它更好地为您工作。但首先让我们更好地了解它是如何工作的,以及为什么你会看到你所做的行为。

当您打开 TCP 连接时,TCP 使用 3 次握手来建立连接。客户端发送一个SYN,服务器响应SYN+ACK,然后客户端回送一个ACK。如果双方都没有尝试发送任何东西,连接就会闲置在那里。您可以从机器上拔下电缆。一棵树可能会倒下并破坏您的互联网服务。互联网提供商可以来修复您的互联网服务,您可以将电缆重新插入以太网端口。然后客户端可以写入套接字,它应该被传送到服务器。 (不幸的是,防火墙故意破坏标准,并且您的防火墙 可能 在您等待 ISP 修复您的服务时决定使连接超时。)但是,如果您尝试建立另一个连接当电缆被拔掉时,TCP 将尝试发送 SYN,并且很可能发现“没有到主机的路由”。所以它无法建立新的连接。

如果您在 Internet 服务中断时尝试写入套接字,TCP 将尝试发送数据并等待来自服务器的 ACK。在重传超时后,如果它没有收到 ACK,它将重试并在超时时按指数方式后退。通常在尝试 15 次后它就会放弃,这通常需要半小时到一个半小时。

如您所见,TCP 试图在面对故障时保持弹性,而您希望非常快速地了解故障。需要对连接失败做出快速反应的系统(例如通常在连接失败时取消未结订单的电子证券交易所)通过定期发送心跳消息并在心跳过期时采取行动来将此作为更高级别协议的一部分进行处理。

但是如果您无法控制协议,可以使用一些套接字选项来改善这种情况。 SO_KEEPALIVE导致TCP周期性发送keepalive包,最终会超时,具体取决于TCP_KEEPIDLE、TCP_KEEPINTVL、TCP_KEEPCNT的设置。 TCP_USER_TIMEOUT 允许您为写入套接字的数据可以保持未确认的时间设置超时。

这两个选项究竟如何工作和交互取决于实现,您必须考虑在没有未确认数据、有未确认数据以及消费者速度慢导致零 window。通常建议将它们与 TCP_USER_TIMEOUT 一起使用设置为 (TCP_KEEPIDLE + TCP_KEEPINTVL*TCP_KEEPCNT) * 1000 以获得一致的结果。

我们的朋友 Cloudflair 很好地 Blog entry 关于它们究竟如何协同工作,但不幸的是 Linux。对于 Windows.

,我不知道有什么比这更全面的了