0

像许多人一样,我一直在研究测试 TCP 会话是否处于活动/活动状态。有太多半有效的解决方案似乎是一个不必要的难题。一个连接在测试自己之前什么都不知道。然后尝试发送可能会成功,尽管连接实际上已丢失。轮询似乎会为连接提供误报。某些服务器配置为不响应 ping。唯一真正的测试似乎是尝试建立新的连接并感知尝试是否成功。这似乎是不必要的笨拙,但协议没有一种轻量级的方式来回答“在这个特定的时刻,是否可以将数据从客户端传输到服务器并验证它是否被接收”的问题,这似乎有点疯狂?

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

我错过了什么?

4

1 回答 1

1

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 允许您设置写入套接字的数据可以保持未确认状态的超时时间。

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

我们的朋友 Cloudflair 有一篇很好的博客文章,介绍了它们究竟是如何协同工作的,但不幸的是在 Linux 上。对于 Windows,我不知道有什么比这更全面的。

于 2020-09-17T16:35:45.977 回答