我听说过HTTP保持活动状态,但现在我想打开与远程服务器的套接字连接。
现在,此套接字连接将永远保持打开状态,还是与HTTP保持活动类似的超时限制?
Answers:
TCP套接字保持打开状态,直到关闭为止。
就是说,在没有实际发送数据的情况下很难检测到断开的连接(断开,例如在路由器死机等情况下,而不是关闭的),因此大多数应用程序每隔一段时间就会执行某种ping / pong反应,以确保该连接实际上仍然有效。
现在,此套接字连接将永远保持打开状态,还是与HTTP保持活动类似的超时限制?
简短的答案是不,它不会永远开放,可能会在几个小时后超时。因此是存在的超时时间,并且它通过强制执行TCP保持活动。
如果要在计算机上配置“保持活动”超时,请参阅下面的“更改TCP超时”部分。否则,请通读其余的答案,以了解TCP Keep-Alive的工作方式。
TCP连接由两个套接字组成,在连接的两端各一个。当一方要终止连接时,它将发送RST
另一方确认的数据包,并且双方均关闭其套接字。
但是,在此之前,双方都将无限期地保持插座打开。这样就留下了一侧可能有意或由于某些错误而没有通过通知另一端而关闭其插槽的可能性RST
。为了检测这种情况并关闭陈旧的连接,使用了TCP Keep Alive进程。
有三个可配置的属性确定“保持活动”的工作方式。在Linux上,它们是1:
tcp_keepalive_time
tcp_keepalive_probes
tcp_keepalive_intvl
该过程如下所示:
tcp_keepalive_time
几秒钟,则发送一个空ACK
数据包。1个ACK
了自己的响应?
tcp_keepalive_intvl
几秒钟,然后再发送一次ACK
ACK
发送的探测数量相等tcp_keepalive_probes
。RST
并终止连接。在大多数操作系统上,默认情况下会启用此过程,因此,一旦另一端在2小时11分钟(7200秒+ 75 * 9秒)无响应后,就会定期删除无效的TCP连接。
由于默认情况下直到一个连接闲置了两个小时才启动该过程,所以过时的TCP连接可能会保留很长的时间才能被删除。这对于昂贵的连接(例如数据库连接)尤其有害。
根据RFC 1122 4.2.3.6,响应和/或中继TCP Keep-Alive数据包是可选的:
实施者可以在其TCP实施中包括“保持活动”,尽管这种做法未被普遍接受。如果包括保持活动,则应用程序必须能够为每个TCP连接打开或关闭它们,并且必须默认为关闭。
...
切记,不包含任何数据的ACK段不能通过TCP可靠地传输,这一点非常重要。
原因是“保持活动”数据包不包含任何数据,也不是严格必需的,如果使用过多,则有可能堵塞互连网的管道。
但是实际上,我的经验是,随着带宽的降低,这种担忧随着时间的流逝而逐渐减少。因此,通常不会丢弃保持活动数据包。例如,Amazon EC2文档提供了对Keep-Alive的间接认可,因此,如果您使用AWS托管,则可以安全地依赖Keep-Alive,但里程可能会有所不同。
不幸的是,由于TCP连接是在操作系统级别上进行管理的,因此Java不支持在每个套接字级别(例如in中)配置超时java.net.Socket
。我发现了一些尝试3,使用Java本机接口(JNI)创建Java套接字,这些套接字调用本机代码来配置这些选项,但是似乎没有一个被社区广泛采用或支持。
相反,您可能被迫将您的配置应用于整个操作系统。请注意,此配置将影响整个系统上运行的所有TCP连接。
当前配置的TCP Keep-Alive设置位于
/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
值得注意的是,相对于使用秒数的Linux ,Mac OS X以毫秒为单位定义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 Keep-Alive设置,网址为:
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters
脚注
1.有关man tcp
详细信息,请参阅。
2.此数据包通常被称为“保持活动”数据包,但在TCP规范内,它只是一个常规ACK
数据包。诸如Wireshark之类的应用程序可以通过对包含在套接字上的先前通信进行参考的序列和确认号的元分析,将其标记为“保持活动”数据包。
3.我从基本的Google搜索中发现的一些示例是lucwilliams / JavaLinuxNet和flonatel / libdontdie。
$ no -a | grep tcp_keep
命令查询当前的TCP Keep-Alive设置。
您正在寻找SO_KEEPALIVE套接字选项。
在Java Socket技术API自曝“保活”通过应用程序setKeepAlive
和getKeepAlive
方法。
编辑:SO_KEEPALIVE是在OS网络协议栈中实现的,而没有发送任何“真实”数据。保持活动间隔取决于操作系统,并且可以通过内核参数进行调整。
由于未发送任何数据,因此SO_KEEPALIVE仅可以测试网络连接的活动性,而不能测试套接字连接到的服务的活动性。为了测试后者,您需要实现一些涉及向服务器发送消息并获得响应的操作。
TCP keepalive和HTTP keepalive是非常不同的概念。在TCP中,keepalive是发送来检测陈旧连接的管理数据包。在HTTP中,keepalive表示持久连接状态。
这来自TCP规范,
仅当在一定间隔内未收到连接的数据或确认数据包时,才必须发送保持活动数据包。该间隔必须是可配置的,并且默认必须不少于两个小时。
如您所见,对于大多数应用程序,默认的TCP Keepalive间隔太长。您可能必须在应用程序协议中添加keepalive。
HTTP/1.0
每个请求/响应中都需要重新连接到服务器。因为HTTP/1.1
他们引入了一个Keep-Alive
标头,在处理完响应以方便请求更多文件并允许“流水线化”后,该标头可用于触发服务器不终止连接。发送多个请求,然后等待所有数据返回。
如果您正在伪装成NAT(如今大多数家庭用户都在使用)中,则外部端口池将是有限的,并且这些端口必须在TCP连接之间共享。因此,如果在特定时间段内未发送任何数据,则伪装的NAT倾向于假定连接已终止。
此问题和其他此类问题(在两个端点之间的任何地方)可能意味着如果您在合理的空闲时间之后尝试发送数据,则连接将不再“起作用”。但是,在尝试发送数据之前,您可能不会发现这一点。
使用Keepalive不仅可以减少连接中断的可能性,还可以使您更快地发现断开的连接。
这是一些有关keepalive的补充文献,对它进行了更详细的解释。
http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO
由于Java不允许您控制实际的Keepalive时间,因此,如果您使用的是Linux内核(或基于proc的OS),则可以使用示例更改它们。
在JAVA Socket中-TCP连接是在OS级别上进行管理的,java.net.Socket不提供任何内置功能来为每个套接字级别的keepalive数据包设置超时。但是我们可以为Java套接字启用keepalive选项,但是默认情况下,在过时的tcp连接之后,它需要2小时11分钟(7200秒)才能处理。在吹扫之前,这会导致连接很长一段时间。因此,我们找到了一些使用Java本机接口(JNI)的解决方案,该解决方案调用本机代码(c ++)来配置这些选项。
**** Windows操作系统****
在Windows操作系统中,keepalive_time和keepalive_intvl可以配置,但是tcp_keepalive_probes不能更改。默认情况下,初始化TCP套接字时,将keep-alive超时设置为2小时,而keep-alive间隔设置为1秒。保持活动超时的系统范围默认值是可以通过KeepAliveTime注册表设置来控制的,该设置的值以毫秒为单位。
在Windows Vista和更高版本上,保持活动状态探查(数据重新传输)的数量设置为10,并且无法更改。
在Windows Server 2003,Windows XP和Windows 2000上,“保持活动”探针的默认设置为5。“保持活动”探针的数量是可控制的。对于Windows,Winsock IOCTLs库用于配置tcp-keepalive参数。
int WSAIoctl(SocketFD,//标识套接字的描述符SIO_KEEPALIVE_VALS,// dwIoControlCode(LPVOID)lpvInBuffer,//指向tcp_keepalive结构(DWORD)的指针cbInBuffer,//输入缓冲区的长度为NULL,//输出缓冲区0,//输出缓冲区(LPDWORD)lpcbBytesReturned,//返回的字节数NULL,// OVERLAPPED结构NULL //完成例程);
Linux操作系统
Linux内置了对keepalive的支持,需要启用TCP / IP网络才能使用它。程序必须使用setsockopt接口请求对套接字的保持活动控制。
int setsockopt(int套接字,int级别,int optname,const void * optval,socklen_t optlen)
每个客户端套接字都将使用java.net.Socket创建。每个套接字的文件描述符ID将使用Java反射检索。
对于Windows,根据Microsoft文档