TCP连接何时被认为是空闲的?

15

我需要在所有连接上启用TCP keepalive,并且现在我正在努力处理我们的测试用例结果。 我认为这是因为我并不真正了解第一个keepalive探测发送的时间。 我在Linux文档中读到以下内容,有关tcp_keepalive_time

最后数据包发送(简单的ACK不被视为数据)和第一个keepalive探测之间的间隔; 在标记需要保持连接之后,此计数器不再使用

其他一些来源声明这是连接空闲的时间,但它们没有进一步定义这意味着什么。 我还查阅了Stevens以找到更正式的定义,因为我想知道在考虑重新传输时,“最后发送的数据包”实际上意味着什么。

在我的测试用例中,我有一个连接,其中数据仅从服务器以相当高的速率发送到客户端。 为了测试keepalive,我们拔掉了客户端NIC上的电缆。 我现在可以看到网络堆栈尝试发送数据并进入重传状态,但未发送keep alive探测。 正确吗,即在重新传输期间不发送keepalive探测?


如果您正在以相当高的速率发送数据,则首先启用TCP keepalive的要求就没有意义。 - user207421
@EJP 我们还有其他连接,例如不发送任何数据的连接,以及仅以低速率发送数据的连接。此外,这是我们客户直接强制要求的要求。他们在全球范围内使用它。 - Jens
我假设你正在提到在所有连接上设置SO_KEEPALIVE(默认为“关闭”)? 如果是这样,那么只有在之后一段时间(默认值在Linux上为2小时)才会看到保持活动数据包,然后拔插技巧应该有效(如果它没有发送其他数据)。 - rogerdpack
@rogerdpack 是的,我们不得不默认启用所有连接的保持活动功能,因为这是客户的强制要求。第一个保持活动数据包发送的时间也包括TCP重试时间。cnicutar的回答提供了详细信息。 - Jens
1个回答

25
我有一个连接,数据只从服务器以相当高的速率发送到客户端。
那么你将永远看不到保持活动状态信息。当"线上静音"时,才会发送保持活动状态信息。RFC1122解释了一些关于保持活动状态信息的内容。
"保持活动"机制定期探测连接的另一端,在连接处于空闲状态时,即使没有要发送的数据也会进行探测。
回到你的问题:
有些其他来源表示这是连接空闲的时间,但它们没有进一步定义这意味着什么。
这是TCP在向对等方发出"嘿!还活着吗?"之前等待的时间。
$ cat /proc/sys/net/ipv4/tcp_keepalive_time
7200

换句话说,您一直在使用TCP连接,效果非常好。然而,在过去的两个小时里没有任何数据需要发送。假设该连接仍然存在合理吗?假设中间所有的中间盒子仍然保留有关您的连接的状态也是合理的吗?不同意见不断变化,而保持活动状态并不是RFC793的一部分。
TCP规范不包括保持活动状态的机制,因为这可能会导致:(1)在短暂的互联网故障期间导致完全良好的连接中断;(2)消耗不必要的带宽(“如果没有人使用连接,谁在乎它是否仍然存在?”)。
为了测试保持连接功能,我们拔掉了客户端网卡上的电缆。
这不是在测试保持连接功能。这是在测试TCP重传策略,即TCP尝试多少次以及多久才能成功传递消息。在Linux系统中,这(可能)最终会测试net.ipv4.tcp_retries2
重试多少次才能杀死活动的TCP连接。RFC 1122表示,该限制应该比100秒更长。这是一个太小的数字。默认值15对应于RTO取决于13-30分钟。
但是RFC5482 - TCP用户超时选项提供了更多影响它的方法。
回到问题:
在重传期间是否发送保持连接探测包是正确的吗?
很合理:TCP已经试图从另一个对等方获取响应,空的keepalive将是多余的。

Linux特定的选项(2.4+)影响保持连接选项的参数

  • TCP_KEEPCNT 在断开连接之前,TCP应发送的最大心跳探测数。

  • TCP_KEEPIDLE 如果在此套接字上设置了SO_KEEPALIVE套接字选项,则连接需要保持空闲的时间(以秒为单位),然后TCP开始发送心跳探测。

  • TCP_KEEPINTVL 在各个心跳探测之间过去的时间(以秒为单位)。

Linux特定的选项(2.6.37+)影响TCP用户超时的参数

TCP_USER_TIMEOUT 在TCP强制关闭连接之前,传输的数据可以在未得到确认的情况下保留的最长时间(以毫秒为单位)。

因此,例如您的应用程序可以使用此选项来确定当没有连接时连接保持的时间(类似于您的NIC拔出示例)。例如,如果您有理由相信客户端会回来(也许他们关闭了笔记本电脑盖子?网络连接不稳定?),您可以指定一个12小时的超时时间,当他们回来时,连接仍将正常运行。

2
FYI,Linux 2.4+具有TCP_KEEPIDLETCP_KEEPINTVLTCP_KEEPCNT选项,用于setsockopt()设置探测开始前的空闲时间、探测之间的时间间隔以及要发送的最大探测次数。 - Remy Lebeau
@RemyLebeau 很好。随意编辑答案以指出这一点! - cnicutar
@cnicutar,你有参考资料可以描述在重传期间不发送保持活动探测吗?似乎这因系统而异,例如在Windows上似乎不同。 - Jens
@Jens 我没有源代码。保持发送keepalive探测并不违法,但这没有太多意义:如果TCP已经在发送数据,那么对方已经有理由ACK(这将证明连接是活动的)。 - cnicutar
@cnicutar 很棒的回答。如果在Linux上也包括有关TCP_USER_TIMEOUT的信息,它可能会稍微改进一下。当搜索有关为什么仅在空闲或等待未到达数据的连接上保持活动状态时,OP和其他人似乎也想知道如何设置每个连接的重传超时。 - Kurt M
@KurtM 我添加了更多细节。请随意编辑答案,以添加您认为有用的任何内容。 - cnicutar

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