TCP 套接字连接是否具有“保持活动状态”?
我听说过 HTTP keep-alive,但现在我想打开与远程服务器的套接字连接。
现在,此套接字连接是否会永远保持打开状态,或者是否存在与 HTTP keep-alive 类似的超时限制?
I have heard of HTTP keep-alive but for now I want to open a socket connection with a remote server.
Now will this socket connection remain open forever or is there a timeout limit associated with it similar to HTTP keep-alive?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
简短的回答是是,通过TCP Keep-Alive强制执行超时,所以不会,套接字不会永远保持打开状态,但可能会在几个后超时>小时。
如果您想在计算机上配置保持活动超时,请参阅下面的“更改 TCP 超时”部分。否则,请通读答案的其余部分,了解 TCP Keep-Alive 的工作原理。
简介
TCP 连接由两个套接字组成,连接的每一端各有一个。当一方想要终止连接时,它会发送一个 FIN 数据包,另一方确认该数据包并关闭其套接字。
然而,在此之前,双方都将无限期地保持套接字打开。这就留下了一种可能性,即一侧可能有意或由于某些错误而关闭其套接字,而不通过 FIN 通知另一端。为了检测这种情况并关闭过时的连接,使用 TCP Keep Alive 过程。
保持活动过程
三个可配置属性决定保持活动如何工作。在 Linux 上,它们是1:
tcp_keepalive_time
tcp_keepalive_probes
tcp_keepalive_intvl
该过程的工作原理如下:
tcp_keepalive_time
秒,则发送一个空ACK
数据包。1ACK
?tcp_keepalive_intvl
秒,然后发送另一个ACK
ACK
探测数量等于tcp_keepalive_probes
。RST
并终止连接。大多数操作系统默认启用此过程,因此一旦另一端在 2 小时 11 分钟(7200 秒 + 75 * 9 秒)。
陷阱
2 小时默认值
由于默认情况下只有连接空闲两小时后进程才会启动,因此过时的 TCP 连接在被修剪之前可能会停留很长时间。这对于昂贵的连接(例如数据库连接)尤其有害。
Keep-Alive 是可选的,
根据 RFC 1122 4.2.3.6, 响应和/或中继 TCP Keep-Alive 数据包是可选的:
原因是“保持活动”数据包不包含任何数据,也不是绝对必要的,如果过度使用,可能会堵塞互联网络的管道。
但在实践中,我的经验是,随着带宽变得更便宜,这种担忧随着时间的推移而减少;因此,Keep-Alive 数据包通常不会被丢弃。例如,Amazon EC2 文档给出了间接认可的 Keep-Alive,因此,如果您使用 AWS 进行托管,您可能可以安全地依赖 Keep-Alive,但您的情况可能会有所不同。
更改
每个套接字的
TCP 超时2022 更新: 显然,从 Java 11 开始,您可以在 Java TCP 套接字本身上设置这些。
不幸的是,由于 TCP 连接是在操作系统级别上管理的,旧版本的 Java 不支持在每个套接字级别上配置超时,例如在
java 中.net.Socket
。我发现了一些尝试3使用 Java 本机接口 (JNI) 创建调用本机代码来配置这些选项的 Java 套接字,但似乎没有一个得到广泛的社区采用或支持。相反,您可能被迫将您的配置应用到整个操作系统。请注意,此配置将影响整个系统上运行的所有 TCP 连接。
Linux
当前配置的 TCP Keep-Alive 设置可以在
/proc/sys/net/ipv4/tcp_keepalive_time
/proc/sys/net/ipv4/tcp_keepalive_probes
/proc/sys/net/ipv4/tcp_keepalive_intvl
您可以像这样更新其中任何一个:
此类更改不会在重新启动后持续存在。要进行持久更改,请使用
sysctl
:Mac OS X
当前配置的设置可以使用
sysctl
查看:值得注意的是,Mac OS X 定义了
keepidle
keepintvl
以毫秒为单位,而 Linux 使用秒。可以使用 sysctl 设置这些属性,它将在重新启动后保留这些设置:
或者,您可以将它们添加到
/etc/sysctl.conf
(如果没有,则创建该文件)不存在)。Windows
我没有要确认的 Windows 计算机,但您应该在注册表中找到相应的 TCP Keep-Alive 设置
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters
< em>脚注
1.请参阅
man tcp
了解更多信息。2.该数据包通常称为“Keep-Alive”数据包,但在 TCP 规范中,它只是一个常规的 ACK 数据包。像 Wireshark 这样的应用程序能够通过对序列和确认号进行元分析来将其标记为“保持活动”数据包,参考套接字上的先前通信。
3.我从基本的 Google 搜索中找到的一些示例是 lucwilliams/JavaLinuxNet 和 flonatel/libdontdie。
The short answer is yes there is a timeout enforced via TCP Keep-Alive, so no the socket won't remain open forever but will probably time out after a few hours.
If you would like to configure the Keep-Alive timeout on your machine, see the "Changing TCP Timeouts" section below. Otherwise read through the rest of the answer to learn how TCP Keep-Alive works.
Introduction
TCP connections consist of two sockets, one on each end of the connection. When one side wants to terminate the connection, it sends an
FIN
packet which the other side acknowledges and both close their sockets.Until that happens, however, both sides will keep their socket open indefinitely. This leaves open the possibility that one side may close their socket, either intentionally or due to some error, without informing the other end via
FIN
. In order to detect this scenario and close stale connections the TCP Keep Alive process is used.Keep-Alive Process
There are three configurable properties that determine how Keep-Alives work. On Linux they are1:
tcp_keepalive_time
tcp_keepalive_probes
tcp_keepalive_intvl
The process works like this:
tcp_keepalive_time
seconds, send a single emptyACK
packet.1ACK
of its own?tcp_keepalive_intvl
seconds, then send anotherACK
ACK
probes that have been sent equalstcp_keepalive_probes
.RST
and terminate the connection.This process is enabled by default on most operating systems, and thus dead TCP connections are regularly pruned once the other end has been unresponsive for 2 hours 11 minutes (7200 seconds + 75 * 9 seconds).
Gotchas
2 Hour Default
Since the process doesn't start until a connection has been idle for two hours by default, stale TCP connections can linger for a very long time before being pruned. This can be especially harmful for expensive connections such as database connections.
Keep-Alive is Optional
According to RFC 1122 4.2.3.6, responding to and/or relaying TCP Keep-Alive packets is optional:
The reasoning being that Keep-Alive packets contain no data and are not strictly necessary and risk clogging up the tubes of the interwebs if overused.
In practice however, my experience has been that this concern has dwindled over time as bandwidth has become cheaper; and thus Keep-Alive packets are not usually dropped. Amazon EC2 documentation for instance gives an indirect endorsement of Keep-Alive, so if you're hosting with AWS you are likely safe relying on Keep-Alive, but your mileage may vary.
Changing TCP Timeouts
Per Socket
2022 Update: Apparently, as of Java 11, you may be able to set these on the Java TCP Socket itself.
Unfortunately since TCP connections are managed on the OS level, older versions of Java do not support configuring timeouts on a per-socket level such as in
java.net.Socket
. I have found some attempts3 to use Java Native Interface (JNI) to create Java sockets that call native code to configure these options, but none appear to have widespread community adoption or support.Instead, you may be forced to apply your configuration to the operating system as a whole. Be aware that this configuration will affect all TCP connections running on the entire system.
Linux
The currently configured TCP Keep-Alive settings can be found in
/proc/sys/net/ipv4/tcp_keepalive_time
/proc/sys/net/ipv4/tcp_keepalive_probes
/proc/sys/net/ipv4/tcp_keepalive_intvl
You can update any of these like so:
Such changes will not persist through a restart. To make persistent changes, use
sysctl
:Mac OS X
The currently configured settings can be viewed with
sysctl
:Of note, Mac OS X defines
keepidle
andkeepintvl
in units of milliseconds as opposed to Linux which uses seconds.The properties can be set with
sysctl
which will persist these settings across reboots:Alternatively, you can add them to
/etc/sysctl.conf
(creating the file if it doesn't exist).Windows
I don't have a Windows machine to confirm, but you should find the respective TCP Keep-Alive settings in the registry at
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters
Footnotes
1. See
man tcp
for more information.2. This packet is often referred to as a "Keep-Alive" packet, but within the TCP specification it is just a regular
ACK
packet. Applications like Wireshark are able to label it as a "Keep-Alive" packet by meta-analysis of the sequence and acknowledgement numbers it contains in reference to the preceding communications on the socket.3. Some examples I found from a basic Google search are lucwilliams/JavaLinuxNet and flonatel/libdontdie.
TCP 套接字保持打开状态直至关闭。
也就是说,在不实际发送数据的情况下很难检测到断开的连接(断开的,如路由器死机等,而不是关闭的),因此大多数应用程序时不时地进行某种 ping/pong 反应,只是为了确保连接实际上仍然有效。
TCP sockets remain open till they are closed.
That said, it's very difficult to detect a broken connection (broken, as in a router died, etc, as opposed to closed) without actually sending data, so most applications do some sort of ping/pong reaction every so often just to make sure the connection is still actually alive.
您正在寻找 SO_KEEPALIVE 套接字选项。
Java Socket API 公开了“keep-alive” " 通过
setKeepAlive
和getKeepAlive
方法发送给应用程序。编辑:SO_KEEPALIVE 在操作系统网络协议栈中实现,而不发送任何“真实”数据。保持活动间隔取决于操作系统,并且可以通过内核参数进行调整。
由于没有发送数据,SO_KEEPALIVE只能测试网络连接的活跃度,而不能测试套接字所连接的服务的活跃度。要测试后者,您需要实现一些涉及向服务器发送消息并获取响应的内容。
You are looking for the SO_KEEPALIVE socket option.
The Java Socket API exposes "keep-alive" to applications via the
setKeepAlive
andgetKeepAlive
methods.EDIT: SO_KEEPALIVE is implemented in the OS network protocol stacks without sending any "real" data. The keep-alive interval is operating system dependent, and may be tuneable via a kernel parameter.
Since no data is sent, SO_KEEPALIVE can only test the liveness of the network connection, not the liveness of the service that the socket is connected to. To test the latter, you need to implement something that involves sending messages to the server and getting a response.
TCP keepalive 和 HTTP keepalive 是非常不同的概念。在 TCP 中,保活是发送用于检测失效连接的管理数据包。在HTTP中,keepalive表示持久连接状态。
这是来自 TCP 规范,
只有当在一定时间间隔内没有收到连接的数据或确认数据包时,才必须发送保持活动数据包。这个间隔必须是可配置的,并且必须默认不少于两个小时。
正如您所看到的,默认的 TCP keepalive 间隔对于大多数应用程序来说太长了。您可能必须在应用程序协议中添加 keepalive。
TCP keepalive and HTTP keepalive are very different concepts. In TCP, the keepalive is the administrative packet sent to detect stale connection. In HTTP, keepalive means the persistent connection state.
This is from TCP specification,
Keep-alive packets MUST only be sent when no data or acknowledgement packets have been received for the connection within an interval. This interval MUST be configurable and MUST default to no less than two hours.
As you can see, the default TCP keepalive interval is too long for most applications. You might have to add keepalive in your application protocol.
如果您位于伪装的 NAT 后面(就像当今大多数家庭用户一样),则外部端口池有限,并且这些端口必须在 TCP 连接之间共享。因此,如果在特定时间段内没有发送数据,伪装 NAT 往往会假设连接已终止。
此问题和其他此类问题(两个端点之间的任何位置)可能意味着,如果您尝试在合理的空闲期后发送数据,连接将不再“工作”。但是,在您尝试发送数据之前,您可能不会发现这一点。
使用 keepalive 既可以减少连接在某个地方被中断的可能性,也可以让您更快地发现连接中断。
If you're behind a masquerading NAT (as most home users are these days), there is a limited pool of external ports, and these must be shared among the TCP connections. Therefore masquerading NATs tend to assume a connection has been terminated if no data has been sent for a certain time period.
This and other such issues (anywhere in between the two endpoints) can mean the connection will no longer "work" if you try to send data after a reasonble idle period. However, you may not discover this until you try to send data.
Using keepalives both reduces the chance of the connection being interrupted somewhere down the line, and also lets you find out about a broken connection sooner.
这里有一些关于 keepalive 的补充文献,其中更详细地解释了它。
http://www.tldp.org/HOWTO/html_single/TCP-Keepalive- HOWTO
由于 Java 不允许您控制实际的 keepalive 时间,因此如果您使用的是 Linux 内核(或基于 proc 的操作系统),则可以使用示例来更改它们。
Here is some supplemental literature on keepalive which explains it in much finer detail.
http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO
Since Java does not allow you to control the actual keepalive times, you can use the examples to change them if you're using a Linux kernel (or proc based OS).
对于 Windows,根据 Microsoft 文档
= 2 小时) - 类似于 tcp_keepalive_time
For Windows according to Microsoft docs
= 2 hours) - analogue to tcp_keepalive_time
在 JAVA Socket – TCP 连接在操作系统级别进行管理,java.net.Socket 不提供任何内置函数来为每个套接字级别的 keepalive 数据包设置超时。但是我们可以为 java 套接字启用 keepalive 选项,但默认情况下,在过时的 tcp 连接后需要 2 小时 11 分钟(7200 秒)才能处理。此原因连接在清除之前将保持很长一段时间。因此,我们找到了一些解决方案,使用调用本机代码(c++)的Java本机接口(JNI)来配置这些选项。
Windows操作系统
在Windows操作系统中keepalive_time & keepalive_intvl 可以配置,但 tcp_keepalive_probes 不能更改。默认情况下,当 TCP 套接字初始化时,将保持活动超时设置为 2 小时,将保持活动间隔设置为 1 秒。保持活动超时的默认系统范围值可通过 KeepAliveTime 注册表设置进行控制,该设置采用以毫秒为单位的值。
在 Windows Vista 及更高版本中,保持活动探测(数据重新传输)的数量设置为 10 并且无法更改。
在Windows Server 2003、Windows XP和Windows 2000上,保活探针的数量默认设置为5。保活探针的数量是可控的。对于 Windows,Winsock IOCTLs 库用于配置 tcp-keepalive 参数。
Linux 操作系统
Linux 内置了对 keepalive 的支持,需要启用 TCP/IP 网络才能使用它。程序必须使用setsockopt 接口请求对其套接字进行保活控制。
int setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen)
每个客户端套接字都将使用 java.net.Socket 创建。每个套接字的文件描述符 ID 将使用 java 反射进行检索。
In JAVA Socket – TCP connections are managed on the OS level, java.net.Socket does not provide any in-built function to set timeouts for keepalive packet on a per-socket level. But we can enable keepalive option for java socket but it takes 2 hours 11 minutes (7200 sec) by default to process after a stale tcp connections. This cause connection will be availabe for very long time before purge. So we found some solution to use Java Native Interface (JNI) that call native code(c++) to configure these options.
Windows OS
In windows operating system keepalive_time & keepalive_intvl can be configurable but tcp_keepalive_probes cannot be change.By default, when a TCP socket is initialized sets the keep-alive timeout to 2 hours and the keep-alive interval to 1 second. The default system-wide value of the keep-alive timeout is controllable through the KeepAliveTime registry setting which takes a value in milliseconds.
On Windows Vista and later, the number of keep-alive probes (data retransmissions) is set to 10 and cannot be changed.
On Windows Server 2003, Windows XP, and Windows 2000, the default setting for number of keep-alive probes is 5. The number of keep-alive probes is controllable. For windows Winsock IOCTLs library is used to configure the tcp-keepalive parameters.
Linux OS
Linux has built-in support for keepalive which is need to be enabling TCP/IP networking in order to use it. Programs must request keepalive control for their sockets using the setsockopt interface.
int setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen)
Each client socket will be created using java.net.Socket. File descriptor ID for each socket will retrieve using java reflection.