现在这个套接字连接是否会永远保持打开状态,或者是否存在与之相关的超时限制,类似于HTTP keep-alive?
简短的回答是,是的,有一个超时,它通过TCP Keep-Alive强制执行。
如果要配置保持活动超时,请参阅下面的“更改TCP超时”部分。
介绍
TCP连接由两个插槽组成,每个插槽位于连接的两端。 当一方想要终止连接时,它会发送另一方确认的ACK数据包并关闭其套接字。
然而,在此之前,双方将无限期地保持其套接字开放。 这使得一方可能有意或由于某些错误而关闭其套接字,而无需通过ACK通知另一端。为了检测这种情况并关闭过时连接,使用TCP Keep Alive进程。
保持活力过程
有三个可配置属性可确定Keep-Alives的工作方式。 在Linux上他们是1:
ACK默认7200秒
ACK默认9
ACK默认75秒
这个过程是这样的:
客户端打开TCP连接
如果连接静默ACK秒,则发送一个空的keepintvl数据包.1
服务器是否以相应的ACK响应?没有等待ACK秒,然后发送另一个keepintvl
重复,直到已发送的ACK探测数等于keepintvl。
如果此时未收到响应,请发送ACK并终止连接。
是:返回第2步
默认情况下,在大多数操作系统上启用此过程,因此一旦另一端无响应2小时11分钟(7200秒+ 75 * 9秒),则会定期修剪死TCP连接。
陷阱
2小时默认值
由于默认情况下连接空闲两小时后才开始进程,因此过时的TCP连接可能会在修剪之前停留很长时间。 这对于诸如数据库连接之类的昂贵连接尤其有害。
Keep-Alive是可选的
根据RFC 1122 4.2.3.6,响应和/或中继TCP Keep-Alive数据包是可选的:
实现者可以在其TCP实现中包含“keep-alives”, 虽然这种做法并未得到普遍接受。 如果保持活着 包含,应用程序必须能够为每个打开或关闭它们 TCP连接,它们必须默认为关闭。
...
这是非常的 重要的是要记住不包含数据的ACK段 由TCP可靠传输。
原因是Keep-Alive数据包不包含任何数据,并且不是严格必要的,如果过度使用,可能会堵塞互联网的管道。
然而,在实践中,我的经验是,随着带宽变得越来越便宜,这种担忧随着时间的推移逐渐减少; 因此,通常不会丢弃Keep-Alive数据包。 例如,亚马逊EC2文档间接认可了Keep-Alive,因此如果您使用AWS托管,您可能会安全地依赖Keep-Alive,但您的里程可能会有所不同。
更改TCP超时
每个插座
不幸的是,由于TCP连接是在操作系统级别上管理的,因此Java不支持在每个套接字级别配置超时,例如ACK.我发现有一些尝试3使用Java本机接口(JNI)创建调用本机代码的Java套接字 配置这些选项,但似乎都没有广泛的社区采用或支持。
相反,您可能被迫将配置作为一个整体应用于操作系统。 请注意,此配置将影响整个系统上运行的所有TCP连接。
Linux的
可以在中找到当前配置的TCP Keep-Alive设置
ACK
ACK
ACK
您可以更新以下任何内容:
# 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
这种变化不会在重启后持续存在。 要进行持久更改,请使用ACK:
sysctl -w net.ipv4.tcp_keepalive_time=180 net.ipv4.tcp_keepalive_probes=3 net.ipv4.tcp_keepalive_intvl=10
Mac OS X.
可以使用ACK查看当前配置的设置:
$ sysctl net.inet.tcp | grep -E "keepidle|keepintvl|keepcnt"
net.inet.tcp.keepidle: 7200000
net.inet.tcp.keepintvl: 75000
net.inet.tcp.keepcnt: 8
值得注意的是,与使用秒的Linux相比,Mac OS X以毫秒为单位定义了ACK和keepintvl。
可以使用ACK设置属性,这将在重新启动后保留这些设置:
sysctl -w net.inet.tcp.keepidle=180000 net.inet.tcp.keepcnt=3 net.inet.tcp.keepintvl=10000
或者,您可以将它们添加到ACK(如果文件不存在,则创建该文件)。
$ cat /etc/sysctl.conf
net.inet.tcp.keepidle=180000
net.inet.tcp.keepintvl=10000
net.inet.tcp.keepcnt=3
视窗
我没有Windows机器来确认,但您应该在注册表中找到相应的TCP Keep-Alive设置
ACK
脚注
1.有关更多信息,请参阅ACK。
2.此数据包通常被称为“保持活动”数据包,但在TCP规范中,它只是一个常规的ACK数据包。 像Wireshark这样的应用程序能够通过元数据分析将其标记为“保持活动”数据包,它包含参考插槽上先前通信所包含的序列和确认号。
我从谷歌基本搜索中找到的一些例子是lucwilliams / JavaLinuxNet和flonatel / libdontdie。