TCP 套接字连接是否具有“保持活动状态”?介绍保活流程戈查斯更改 TCP 超时
我听说过HTTP保持活动状态,但现在我想打开与远程服务器的套接字连接。
现在,此套接字连接将永久保持打开状态,还是存在类似于 HTTP 保持活动状态的超时限制?
我听说过HTTP保持活动状态,但现在我想打开与远程服务器的套接字连接。
现在,此套接字连接将永久保持打开状态,还是存在类似于 HTTP 保持活动状态的超时限制?
TCP 套接字连接是否具有“保持活动状态”?
简短的回答是肯定的,通过TCP Keep-Alive强制执行超时,因此套接字不会永远保持打开状态,但可能会在几个小时后超时。
如果要在计算机上配置保持活动超时,请参阅下面的“更改 TCP 超时”部分。否则,请通读答案的其余部分,以了解 TCP Keep-Alive 的工作原理。
TCP 连接由两个套接字组成,两个套接字位于连接的两端。当一方想要终止连接时,它会发送一个数据包,另一方确认并关闭其套接字。FIN
然而,在此之前,双方都将无限期地保持插座打开。这留下了一种可能性,即一方可能会故意或由于某些错误而关闭其插座,而无需通过 通知另一端。为了检测这种情况并关闭过时的连接,使用 TCP 保持活动状态进程。FIN
有三个可配置的属性用于确定 Keep-Alives 的工作方式。在 Linux 上,它们是1:
tcp_keepalive_time
tcp_keepalive_probes
tcp_keepalive_intvl
该过程的工作原理如下:
tcp_keepalive_time
ACK
ACK
tcp_keepalive_intvl
ACK
ACK
tcp_keepalive_probes
RST
默认情况下,此过程在大多数操作系统上都处于启用状态,因此,一旦另一端无响应 2 小时 11 分钟(7200 秒 + 75 * 9 秒),就会定期修剪失效的 TCP 连接。
由于默认情况下,该过程直到连接空闲两个小时后才会启动,因此过时的 TCP 连接可能会在被修剪之前徘徊很长时间。这对于昂贵的连接(如数据库连接)尤其有害。
根据 RFC 1122 4.2.3.6,响应和/或中继 TCP 保持活动状态数据包是可选的:
实现者可以在其 TCP 实现中包含“保持活动状态”,尽管这种做法并未被普遍接受。如果包括保持活动状态,则应用程序必须能够为每个 TCP 连接打开或关闭它们,并且它们必须默认为关闭。
...
非常重要的是要记住,不包含数据的ACK段不能通过TCP可靠地传输。
理由是Keep-Alive数据包不包含任何数据,也不是严格必要的,如果过度使用,可能会堵塞互通网的管道。
然而,在实践中,我的经验是,随着带宽变得更便宜,这种担忧随着时间的推移而减少。因此,Keep-Alive数据包通常不会被丢弃。例如,Amazon EC2 文档间接认可了 Keep-Alive,因此,如果您使用 AWS 托管,则可能安全地依赖 Keep-Alive,但您的里程可能会有所不同。
遗憾的是,由于 TCP 连接是在操作系统级别上进行管理的,因此 Java 不支持在每个套接字级别(如 中)上配置超时。我发现有一些尝试3 使用 Java Native Interface (JNI) 来创建 Java 套接字,这些套接字调用原生代码来配置这些选项,但似乎没有一个得到社区的广泛采用或支持。java.net.Socket
相反,您可能会被迫将配置作为一个整体应用于操作系统。请注意,此配置将影响整个系统上运行的所有 TCP 连接。
当前配置的 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
可以使用以下命令查看当前配置的设置: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。keepidle
keepintvl
可以设置属性,用于在重新启动后保留这些设置: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 / JavaLinuxNet和flnatel / libdontdie。
TCP 套接字在关闭之前一直保持打开状态。
也就是说,如果不实际发送数据,就很难检测到断开的连接(断开,如路由器死亡等,而不是关闭),因此大多数应用程序每隔一段时间就会做某种ping/pong反应,以确保连接实际上仍然有效。