TCP 套接字连接是否具有“保持活动状态”?介绍保活流程戈查斯更改 TCP 超时

2022-08-31 10:24:46

我听说过HTTP保持活动状态,但现在我想打开与远程服务器的套接字连接。
现在,此套接字连接将永久保持打开状态,还是存在类似于 HTTP 保持活动状态的超时限制?


答案 1

TCP 套接字连接是否具有“保持活动状态”?

简短的回答是肯定的,通过TCP Keep-Alive强制执行超时,因此套接字不会永远保持打开状态,但可能会在几个小时后超时。

如果要在计算机上配置保持活动超时,请参阅下面的“更改 TCP 超时”部分。否则,请通读答案的其余部分,以了解 TCP Keep-Alive 的工作原理。

介绍

TCP 连接由两个套接字组成,两个套接字位于连接的两端。当一方想要终止连接时,它会发送一个数据包,另一方确认并关闭其套接字。FIN

然而,在此之前,双方都将无限期地保持插座打开。这留下了一种可能性,即一方可能会故意或由于某些错误而关闭其插座,而无需通过 通知另一端。为了检测这种情况并关闭过时的连接,使用 TCP 保持活动状态进程。FIN

保活流程

有三个可配置的属性用于确定 Keep-Alives 的工作方式。在 Linux 上,它们是1

  • tcp_keepalive_time
    • 默认值 7200 秒
  • tcp_keepalive_probes
    • 默认值 9
  • tcp_keepalive_intvl
    • 默认值 75 秒

该过程的工作原理如下:

  1. 客户端打开 TCP 连接
  2. 如果连接静默几秒钟,请发送一个空数据包。1 个tcp_keepalive_timeACK
  3. 服务器是否使用自己的相应响应?ACK
      1. 等待几秒钟,然后发送另一个tcp_keepalive_intvlACK
      2. 重复此步骤,直到已发送的探测器数等于 。ACKtcp_keepalive_probes
      3. 如果此时尚未收到响应,请发送 并终止连接。RST
    • :返回步骤 2

默认情况下,此过程在大多数操作系统上都处于启用状态,因此,一旦另一端无响应 2 小时 11 分钟(7200 秒 + 75 * 9 秒),就会定期修剪失效的 TCP 连接。

戈查斯

默认 2 小时

由于默认情况下,该过程直到连接空闲两个小时后才会启动,因此过时的 TCP 连接可能会在被修剪之前徘徊很长时间。这对于昂贵的连接(如数据库连接)尤其有害。

保持活动状态是可选的

根据 RFC 1122 4.2.3.6,响应和/或中继 TCP 保持活动状态数据包是可选的

实现者可以在其 TCP 实现中包含“保持活动状态”,尽管这种做法并未被普遍接受。如果包括保持活动状态,则应用程序必须能够为每个 TCP 连接打开或关闭它们,并且它们必须默认为关闭。

...

非常重要的是要记住,不包含数据的ACK段不能通过TCP可靠地传输。

理由是Keep-Alive数据包不包含任何数据,也不是严格必要的,如果过度使用,可能会堵塞互通网的管道。

然而,在实践中,我的经验是,随着带宽变得更便宜,这种担忧随着时间的推移而减少。因此,Keep-Alive数据包通常不会被丢弃。例如,Amazon EC2 文档间接认可了 Keep-Alive,因此,如果您使用 AWS 托管,则可能安全地依赖 Keep-Alive,但您的里程可能会有所不同。

更改 TCP 超时

每个插槽

遗憾的是,由于 TCP 连接是在操作系统级别上进行管理的,因此 Java 不支持在每个套接字级别(如 中)上配置超时。我发现有一些尝试3 使用 Java Native Interface (JNI) 来创建 Java 套接字,这些套接字调用原生代码来配置这些选项,但似乎没有一个得到社区的广泛采用或支持。java.net.Socket

相反,您可能会被迫将配置作为一个整体应用于操作系统。请注意,此配置将影响整个系统上运行的所有 TCP 连接。

Linux

当前配置的 TCP 保持活动状态设置可在

  • /proc/sys/net/ipv4/tcp_keepalive_time
  • /proc/sys/net/ipv4/tcp_keepalive_probes
  • /proc/sys/net/ipv4/tcp_keepalive_intvl

您可以像这样更新其中任何一个:

# Send first Keep-Alive packet when a TCP socket has been idle for 3 minutes
$ echo 180 > /proc/sys/net/ipv4/tcp_keepalive_time
# Send three Keep-Alive probes...
$ echo 3 > /proc/sys/net/ipv4/tcp_keepalive_probes
# ... spaced 10 seconds apart.
$ echo 10 > /proc/sys/net/ipv4/tcp_keepalive_intvl

此类更改不会在重新启动时持续存在。要进行持久更改,请使用 :sysctl

sysctl -w net.ipv4.tcp_keepalive_time=180 net.ipv4.tcp_keepalive_probes=3 net.ipv4.tcp_keepalive_intvl=10

Mac OS X

可以使用以下命令查看当前配置的设置:sysctl

$ sysctl net.inet.tcp | grep -E "keepidle|keepintvl|keepcnt"
net.inet.tcp.keepidle: 7200000
net.inet.tcp.keepintvl: 75000
net.inet.tcp.keepcnt: 8

值得注意的是,Mac OS X以毫秒为单位定义和,而不是使用秒的Linux。keepidlekeepintvl

可以设置属性,用于在重新启动后保留这些设置:sysctl

sysctl -w net.inet.tcp.keepidle=180000 net.inet.tcp.keepcnt=3 net.inet.tcp.keepintvl=10000

或者,您可以将它们添加到(如果文件不存在,则创建该文件)。/etc/sysctl.conf

$ cat /etc/sysctl.conf
net.inet.tcp.keepidle=180000
net.inet.tcp.keepintvl=10000
net.inet.tcp.keepcnt=3

窗户

我没有要确认的Windows计算机,但您应该在注册表中找到相应的TCP保持活动状态设置

\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters

脚注

1. 请参阅男士 tcp 了解更多信息。

2. 此数据包通常称为“Keep-Alive”数据包,但在 TCP 规范中,它只是一个常规的 ACK 数据包。像Wireshark这样的应用程序能够通过对它所包含的序列和确认编号进行元分析来将其标记为“Keep-Alive”数据包,这些序列和确认编号参考了套接字上的上述通信。

3.我从基本的Google搜索中找到的一些例子是lucwilliams / JavaLinuxNetflnatel / libdontdie


答案 2

TCP 套接字在关闭之前一直保持打开状态。

也就是说,如果不实际发送数据,就很难检测到断开的连接(断开,如路由器死亡等,而不是关闭),因此大多数应用程序每隔一段时间就会做某种ping/pong反应,以确保连接实际上仍然有效。


推荐