Java TCP 套接字连接是否具有“保持活动状态”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1480236/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Does a TCP socket connection have a "keep alive"?
提问by Kevin Boyd
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?
我听说过 HTTP keep-alive,但现在我想打开一个与远程服务器的套接字连接。
现在这个套接字连接是否会永远保持打开状态,或者是否存在与 HTTP 保持活动类似的超时限制?
采纳答案by Matthew Scharley
TCP sockets remain open till they are closed.
TCP 套接字保持打开状态,直到它们关闭。
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.
也就是说,在不实际发送数据的情况下很难检测到断开的连接(断开,如路由器死机等,而不是关闭),因此大多数应用程序每隔一段时间都会进行某种乒乓反应,以确保连接实际上仍然存在。
回答by Stephen C
You are looking for the SO_KEEPALIVE socket option.
您正在寻找 SO_KEEPALIVE 套接字选项。
The Java Socket APIexposes "keep-alive" to applications via the setKeepAlive
and getKeepAlive
methods.
在Java Socket技术API自曝“保活”通过应用程序setKeepAlive
和getKeepAlive
方法。
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.
编辑: SO_KEEPALIVE 在操作系统网络协议栈中实现,而不发送任何“真实”数据。保持活动间隔取决于操作系统,并且可以通过内核参数进行调整。
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.
由于没有数据发送,所以 SO_KEEPALIVE 只能测试网络连接的活跃度,而不是套接字连接到的服务的活跃度。要测试后者,您需要实现一些涉及向服务器发送消息并获得响应的内容。
回答by Artelius
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.
如果您使用伪装的 NAT(就像现在大多数家庭用户一样),则外部端口池是有限的,并且这些端口必须在 TCP 连接之间共享。因此,如果在特定时间段内没有发送数据,则伪装 NAT 往往会假设连接已终止。
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 tryto send data.
这个和其他类似的问题(两个端点之间的任何地方)可能意味着如果您在合理的空闲期后尝试发送数据,连接将不再“工作”。但是,在您尝试发送数据之前,您可能不会发现这一点。
Using keepalives both reducesthe chance of the connection being interrupted somewhere down the line, and also lets you find out about a broken connection sooner.
使用 keepalive 既可以减少连接在线路某处中断的可能性,也可以让您更快地发现连接中断。
回答by ZZ Coder
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.
TCP keepalive 和 HTTP keepalive 是非常不同的概念。在 TCP 中,keepalive 是发送用于检测过时连接的管理数据包。在 HTTP 中,keepalive 表示持久连接状态。
This is from TCP specification,
这是来自 TCP 规范,
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.
如您所见,默认 TCP keepalive 间隔对于大多数应用程序来说太长了。您可能需要在应用程序协议中添加 keepalive。
回答by Jeach
Here is some supplemental literature on keepalive which explains it in much finer detail.
这里有一些关于 keepalive 的补充文献,它更详细地解释了它。
http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO
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).
由于 Java 不允许您控制实际的 keepalive 时间,因此如果您使用的是 Linux 内核(或基于 proc 的操作系统),则可以使用示例来更改它们。
回答by Cory Klein
Now will this socket connection remain open forever or is there a timeout limit associated with it similar to HTTP keep-alive?
现在这个套接字连接是否会永远保持打开状态,或者是否存在与 HTTP 保持活动类似的超时限制?
The short answer is, yes, there is a timeout and it is enforced via TCP Keep-Alive.
简短的回答是,是的,有一个超时,它是通过 TCP Keep-Alive 强制执行的。
If you would like to configure the Keep-Alive timeout, see the "Changing TCP Timeouts" section below.
如果您想配置 Keep-Alive 超时,请参阅下面的“更改 TCP 超时”部分。
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 RST
packet which the other side acknowledges and both close their sockets.
TCP 连接由两个套接字组成,连接的每一端各一个。当一侧想要终止连接时,它发送一个RST
数据包,另一侧确认并关闭它们的套接字。
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 RST
. In order to detect this scenario and close stale connections the TCP Keep Alive process is used.
然而,在此之前,双方将无限期地保持他们的插座打开。这留下了一侧可能有意或由于某些错误而关闭其插座的可能性,而没有通过 通知另一端RST
。为了检测这种情况并关闭过时的连接,使用了 TCP Keep Alive 进程。
Keep-Alive Process
保活过程
There are three configurable properties that determine how Keep-Alives work. On Linux they are1:
有三个可配置的属性决定了 Keep-Alives 的工作方式。在 Linux 上它们是1:
tcp_keepalive_time
- default 7200 seconds
tcp_keepalive_probes
- default 9
tcp_keepalive_intvl
- default 75 seconds
tcp_keepalive_time
- 默认 7200 秒
tcp_keepalive_probes
- 默认 9
tcp_keepalive_intvl
- 默认 75 秒
The process works like this:
这个过程是这样工作的:
- Client opens TCP connection
- If the connection is silent for
tcp_keepalive_time
seconds, send a single emptyACK
packet.1 - Did the server respond with a corresponding
ACK
of its own?- No
- Wait
tcp_keepalive_intvl
seconds, then send anotherACK
- Repeat until the number of
ACK
probes that have been sent equalstcp_keepalive_probes
. - If no response has been received at this point, send a
RST
and terminate the connection.
- Wait
- Yes: Return to step 2
- No
- 客户端打开 TCP 连接
- 如果连接静默
tcp_keepalive_time
几秒钟,则发送一个空ACK
数据包。1 - 服务器是否以
ACK
自己的对应响应?- 不
- 等待
tcp_keepalive_intvl
几秒钟,然后再发送一个ACK
- 重复直到
ACK
已发送的探测数等于tcp_keepalive_probes
。 - 如果此时没有收到响应,发送 a
RST
并终止连接。
- 等待
- 是:返回第 2 步
- 不
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).
大多数操作系统默认启用此过程,因此一旦另一端无响应 2 小时 11 分钟(7200 秒 + 75 * 9 秒),就会定期删除死 TCP 连接。
Gotchas
陷阱
2 Hour Default
2 小时默认值
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.
由于默认情况下连接空闲两个小时后才会启动该过程,因此过时的 TCP 连接在被修剪之前可能会停留很长时间。这对于昂贵的连接(例如数据库连接)尤其有害。
Keep-Alive is Optional
Keep-Alive 是可选的
According to RFC 1122 4.2.3.6, responding to and/or relaying TCP Keep-Alive packets is optional:
根据RFC 1122 4.2.3.6,响应和/或中继 TCP Keep-Alive 数据包是可选的:
Implementors MAY include "keep-alives" in their TCP implementations, although this practice is not universally accepted. If keep-alives are included, the application MUST be able to turn them on or off for each TCP connection, and they MUST default to off.
...
It is extremely important to remember that ACK segments that contain no data are not reliably transmitted by TCP.
实现者可以在他们的 TCP 实现中包含“keep-alives”,尽管这种做法并没有被普遍接受。如果包含 keep-alives,应用程序必须能够为每个 TCP 连接打开或关闭它们,并且它们必须默认为关闭。
...
记住不包含数据的 ACK 段不能被 TCP 可靠地传输是非常重要的。
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.
原因是 Keep-Alive 数据包不包含任何数据,也不是绝对必要的,如果过度使用,可能会堵塞互联网的管道。
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 documentationfor 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.
然而,在实践中,我的经验是,随着带宽变得更便宜,这种担忧随着时间的推移而减少。因此,Keep-Alive 数据包通常不会被丢弃。例如,Amazon EC2 文档对 Keep-Alive 进行了间接认可,因此如果您使用 AWS 托管,您可能可以安全地依赖 Keep-Alive,但您的里程可能会有所不同。
Changing TCP Timeouts
更改 TCP 超时
Per Socket
每个插槽
Unfortunately since TCP connections are managed on the OS level, Java does not support configuring timeouts on a per-socket level such as in java.net.Socket
. I have found some attempts3to 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.
不幸的是,由于 TCP 连接是在操作系统级别管理的,Java 不支持在每个套接字级别上配置超时,例如在java.net.Socket
. 我发现了一些尝试3使用 Java 本机接口 (JNI) 创建调用本机代码来配置这些选项的 Java 套接字,但似乎没有一个得到广泛的社区采用或支持。
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.
相反,您可能被迫将您的配置作为一个整体应用于操作系统。请注意,此配置将影响整个系统上运行的所有 TCP 连接。
Linux
Linux
The currently configured TCP Keep-Alive settings can be found in
当前配置的 TCP Keep-Alive 设置可以在
/proc/sys/net/ipv4/tcp_keepalive_time
/proc/sys/net/ipv4/tcp_keepalive_probes
/proc/sys/net/ipv4/tcp_keepalive_intvl
/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:
您可以像这样更新其中任何一个:
# 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
Such changes will not persist through a restart. To make persistent changes, use sysctl
:
此类更改不会通过重新启动而持续存在。要进行持久更改,请使用sysctl
:
sysctl -w net.ipv4.tcp_keepalive_time=180 net.ipv4.tcp_keepalive_probes=3 net.ipv4.tcp_keepalive_intvl=10
Mac OS X
Mac OS X
The currently configured settings can be viewed with sysctl
:
可以使用以下命令查看当前配置的设置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
Of note, Mac OS X defines keepidle
and keepintvl
in units of milliseconds as opposed to Linux which uses seconds.
值得注意的是,Mac OS X以毫秒为单位定义keepidle
和keepintvl
,而不是使用秒的 Linux。
The properties can be set with sysctl
which will persist these settings across reboots:
可以设置这些属性,sysctl
以便在重新启动时保留这些设置:
sysctl -w net.inet.tcp.keepidle=180000 net.inet.tcp.keepcnt=3 net.inet.tcp.keepintvl=10000
Alternatively, you can add them to /etc/sysctl.conf
(creating the file if it doesn't exist).
或者,您可以将它们添加到/etc/sysctl.conf
(如果文件不存在,则创建该文件)。
$ cat /etc/sysctl.conf
net.inet.tcp.keepidle=180000
net.inet.tcp.keepintvl=10000
net.inet.tcp.keepcnt=3
Windows
视窗
I don't have a Windows machine to confirm, but you should find the respective TCP Keep-Alive settings in the registry at
我没有要确认的 Windows 机器,但您应该在注册表中找到相应的 TCP Keep-Alive 设置:
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters
Footnotes
脚注
1. See man tcp
for more information.
1. 查看man tcp
更多信息。
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.
2. 这个数据包通常被称为“Keep-Alive”数据包,但在 TCP 规范中它只是一个常规ACK
数据包。像 Wireshark 这样的应用程序能够通过元分析它包含的序列和确认号(参考套接字上的先前通信)将其标记为“Keep-Alive”数据包。
3. Some examples I found from a basic Google search are lucwilliams/JavaLinuxNetand flonatel/libdontdie.
3. 我从基本的谷歌搜索中找到的一些例子是lucwilliams/JavaLinuxNet和flonatel/libdontdie。
回答by Suganya Vinayakam
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.
在 JAVA Socket – TCP 连接是在 OS 级别管理的,java.net.Socket 不提供任何内置函数来设置每个套接字级别的 keepalive 数据包超时。但是我们可以为 java socket 启用 keepalive 选项,但默认情况下需要 2 小时 11 分钟(7200 秒)来处理过时的 tcp 连接。此原因连接将在清除之前可用很长时间。因此,我们找到了一些使用 Java 本机接口 (JNI) 调用本机代码 (c++) 来配置这些选项的解决方案。
****Windows OS****
****Windows 操作系统****
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.
在 windows 操作系统中,keepalive_time & keepalive_intvl 可以配置,但 tcp_keepalive_probes 不能改变。默认情况下,当 TCP 套接字初始化时,将保持连接超时设置为 2 小时,保持连接间隔为 1 秒。保持活动超时的默认系统范围值可通过 KeepAliveTime 注册表设置进行控制,该设置以毫秒为单位。
On Windows Vista and later, the number of keep-alive probes (data retransmissions) is set to 10 and cannot be changed.
在 Windows Vista 和更高版本上,保持活动探测(数据重新传输)的数量设置为 10,并且无法更改。
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.
在Windows Server 2003、Windows XP和Windows 2000上,keep-alive探针的数量默认设置为5。keep-alive探针的数量是可控的。对于 windows Winsock IOCTLs 库用于配置 tcp-keepalive 参数。
int WSAIoctl( SocketFD, // descriptor identifying a socket SIO_KEEPALIVE_VALS, // dwIoControlCode (LPVOID) lpvInBuffer, // pointer to tcp_keepalive struct (DWORD) cbInBuffer, // length of input buffer NULL, // output buffer 0, // size of output buffer (LPDWORD) lpcbBytesReturned, // number of bytes returned NULL, // OVERLAPPED structure NULL // completion routine );
int WSAIoctl( SocketFD, // 标识套接字的描述符 SIO_KEEPALIVE_VALS, // dwIoControlCode (LPVOID) lpvInBuffer, // 指向 tcp_keepalive struct (DWORD) cbInBuffer, // 输入缓冲区的长度 NULL, // 输出缓冲区 0, // 的大小输出缓冲区 (LPDWORD) lpcbBytesReturned, // 返回的字节数 NULL, // OVERLAPPED 结构 NULL // 完成例程 );
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.
Linux 内置了对 keepalive 的支持,需要启用 TCP/IP 网络才能使用它。程序必须使用setsockopt 接口为其套接字请求keepalive 控制。
int setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen)
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.
每个客户端套接字都将使用 java.net.Socket 创建。每个套接字的文件描述符 ID 将使用 java 反射检索。
回答by semen
For Windows according to Microsoft docs
根据Microsoft 文档,对于 Windows
- KeepAliveTime (REG_DWORD, milliseconds, by default is not set which means 7,200,000,000 = 2 hours) - analogue to tcp_keepalive_time
- KeepAliveInterval (REG_DWORD, milliseconds, by default is not set which means 1,000 = 1 second) - analogue to tcp_keepalive_intvl
- Since Windows Vista there is no analogue to tcp_keepalive_probes, value is fixed to 10 and cannot be changed
- KeepAliveTime(REG_DWORD,毫秒,默认情况下未设置,这意味着 7,200,000,000 = 2 小时) - 类似于 tcp_keepalive_time
- KeepAliveInterval(REG_DWORD,毫秒,默认情况下未设置,这意味着 1,000 = 1 秒) - 类似于 tcp_keepalive_intvl
- 由于 Windows Vista 没有类似于 tcp_keepalive_probes 的值,因此值固定为 10 且无法更改