TCP套接字连接是否“保持活动”?


84

我听说过HTTP保持活动状态,但现在我想打开与远程服务器的套接字连接。
现在,此套接字连接将永远保持打开状态,还是与HTTP保持活动类似的超时限制?


1
只是为了确保“ http keepalive”通常与套接字keepalive不相关,它讨论了HTTP / 1.1的功能,该功能可保持连接打开以供进一步的请求使用。它仅与TCP keepalive有关,因为它需要检测断开的TCP连接(或者通常仅在有限的时间内保持套接字打开状态)。
eckes,2015年

Answers:


72

TCP套接字保持打开状态,直到关闭为止。

就是说,在没有实际发送数据的情况下很难检测到断开的连接(断开,例如在路由器死机等情况下,而不是关闭的),因此大多数应用程序每隔一段时间就会执行某种ping / pong反应,以确保该连接实际上仍然有效。


4
是个好主意。你不具备,但如果你不这样做,那么你可能不会直到有人竟想做点事检测链路中断。哪些可能是好事,也可能不是好事(或可能或不重要),这取决于您实际要实现的目标。
马修·沙利

1
@Pacerier:取决于协议,因为它完全依赖协议,但是对于基于文本的协议,需要一个文字“ PING”和“ PONG”命令是非常典型的。
马修·沙利

4
@MatthewScharley:这个“乒乓”已经在标准TCP实现中为我们实现,被称为“保持活动”(请参阅​​此问题的另一个流行答案)。有什么理由在应用程序级别实施它吗?
蒂姆·库珀

7
@TimCooper:并非如此。正如我在对其他答案的评论中所强调的那样,TCP实施对于大多数应用程序级需求没有用。您无法按需发送消息,对于大多数操作系统,TCP keepalive超时只能在系统范围内进行配置,并且设置得太高而无法对应用程序普遍使用。
马修·沙利

13
@Tim在应用程序级别保持活动的原因是TCP标准建议将保持活动计时器设置为大于两个小时。从来没有见过没有流量的TCP连接可以幸免。因此,TCP保持活动默认情况下是无用的。
罗伯特·

96

现在,此套接字连接将永远保持打开状态,还是与HTTP保持活动类似的超时限制?

简短的答案是不,它不会永远开放,可能会在几个小时后超时。因此存在超时时间,并且它通过强制执行TCP保持活动

如果要在计算机上配置“保持活动”超时,请参阅下面的“更改TCP超时”部分。否则,请通读其余的答案,以了解TCP Keep-Alive的工作方式。

介绍

TCP连接由两个套接字组成,在连接的两端各一个。当一方要终止连接时,它将发送RST另一方确认的数据包,并且双方均关闭其套接字。

但是,在此之前,双方都将无限期地保持插座打开。这样就留下了一侧可能有意或由于某些错误而没有通过通知另一端而关闭其插槽的可能性RST。为了检测这种情况并关闭陈旧的连接,使用了TCP Keep Alive进程。

保持生命的过程

有三个可配置的属性确定“保持活动”的工作方式。在Linux上,它们是1

  • tcp_keepalive_time
    • 默认7200秒
  • tcp_keepalive_probes
    • 默认9
  • tcp_keepalive_intvl
    • 默认75秒

该过程如下所示:

  1. 客户端打开TCP连接
  2. 如果连接沉默了tcp_keepalive_time几秒钟,则发送一个空ACK数据包。1个
  3. 服务器是否响应ACK了自己的响应?
    • 没有
      1. 等待tcp_keepalive_intvl几秒钟,然后再发送一次ACK
      2. 重复直到ACK发送的探测数量相等tcp_keepalive_probes
      3. 如果此时未收到响应,请发送RST并终止连接。
    • :返回步骤2

在大多数操作系统上,默认情况下会启用此过程,因此,一旦另一端在2小时11分钟(7200秒+ 75 * 9秒)无响应后,就会定期删除无效的TCP连接。

陷阱

2小时默认

由于默认情况下直到一个连接闲置了两个小时才启动该过程,所以过时的TCP连接可能会保留很长的时间才能被删除。这对于昂贵的连接(例如数据库连接)尤其有害。

保持活动是可选的

根据RFC 1122 4.2.3.6,响应和/或中继TCP Keep-Alive数据包是可选的

实施者可以在其TCP实施中包括“保持活动”,尽管这种做法未被普遍接受。如果包括保持活动,则应用程序必须能够为每个TCP连接打开或关闭它们,并且必须默认为关闭。

...

切记,不包含任何数据的ACK段不能通过TCP可靠地传输,这一点非常重要。

原因是“保持活动”数据包不包含任何数据,也不是严格必需的,如果使用过多,则有可能堵塞互连网的管道。

但是实际上,我的经验是,随着带宽的降低,这种担忧随着时间的流逝而逐渐减少。因此,通常不会丢弃保持活动数据包。例如,Amazon EC2文档提供了对Keep-Alive的间接认可,因此,如果您使用AWS托管,则可以安全地依赖Keep-Alive,但里程可能会有所不同。

更改TCP超时

每个插座

不幸的是,由于TCP连接是在操作系统级别上进行管理的,因此Java不支持在每个套接字级别(例如in中)配置超时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

您可以像这样更新任何一个:

# 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

Mac OS X

可以使用以下命令查看当前配置的设置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以毫秒为单位定义keepidlekeepintvl

可以设置属性,这些属性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 / JavaLinuxNetflonatel / libdontdie


非常有帮助,谢谢!一个附加功能:对于Windows,需要重新启动才能使KeepAliveTime的新值生效。
geld0r

在AIX上,可以使用$ no -a | grep tcp_keep命令查询当前的TCP Keep-Alive设置。
JarekPrzygódzki'16

55

您正在寻找SO_KEEPALIVE套接字选项。

Java Socket技术API自曝“保活”通过应用程序setKeepAlivegetKeepAlive方法。

编辑:SO_KEEPALIVE是在OS网络协议栈中实现的,而没有发送任何“真实”数据。保持活动间隔取决于操作系统,并且可以通过内核参数进行调整。

由于未发送任何数据,因此SO_KEEPALIVE仅可以测试网络连接的活动性,而不能测试套接字连接到的服务的活动性。为了测试后者,您需要实现一些涉及向服务器发送消息并获得响应的操作。


4
如果我一个setKeepAlive(true); 时间间隔是多少?... Java是否还会继续以默认时间间隔发送保持活动消息,还是我必须以编程方式进行操作?
凯文·博伊德

3
unixguide.net/network/socketfaq/4.7.shtml包含SO_KEEPALIVE的描述。它不是OP想要的,尽管它我建议的基于协议的选项...但是,每两个小时一次对应用程序并没有多大帮助。
马修·沙利

4
@MatthewScharley关于“默认时间不得少于两个小时” ...意味着它可以少于两个小时吧?
Pacerier

1
@MatthewScharley- “您是对的,但是那是特定于实现的……”。保持活动的时间间隔不能少于两个小时,这将毫无用处,以至于很难想象有人实施它。
斯蒂芬·C

2
@Daniel-替代方法(在Java中)将是手动保持活动状态,如上所述和其他答案。这并不漂亮,但是它可能比操作系统范围内的默认更改更好,因为默认更改可能会破坏系统服务或其他应用程序。
斯蒂芬·C

34

TCP keepalive和HTTP keepalive是非常不同的概念。在TCP中,keepalive是发送来检测陈旧连接的管理数据包。在HTTP中,keepalive表示持久连接状态。

这来自TCP规范,

仅当在一定间隔内未收到连接的数据或确认数据包时,才必须发送保持活动数据包。该间隔必须是可配置的,并且默认必须不少于两个小时。

如您所见,对于大多数应用程序,默认的TCP Keepalive间隔太长。您可能必须在应用程序协议中添加keepalive。


2
您可以修改TCP Keepalive间隔以适合您的应用程序。例如,msdn.microsoft.com
zh

@ZZCoder您能否解释说“在HTTP中,keepalive表示持久连接状态”是什么意思?
Pacerier

1
@Pacerier:在HTTP/1.0每个请求/响应中都需要重新连接到服务器。因为HTTP/1.1他们引入了一个Keep-Alive标头,在处理完响应以方便请求更多文件并允许“流水线化”后,该标头可用于触发服务器不终止连接。发送多个请求,然后等待所有数据返回。
马修·沙利

基本上,这意味着许多HTTP请求将/应该重用相同的TCP-Connection(这些连接也可能具有保持活动状态,但不符合HTTP的要求,因此本质上是一个不同的概念)。
IgorČordaš2014年

24

如果您正在伪装成NAT(如今大多数家庭用户都在使用)中,则外部端口池将是有限的,并且这些端口必须在TCP连接之间共享。因此,如果在特定时间段内未发送任何数据,则伪装的NAT倾向于假定连接已终止。

此问题和其他此类问题(在两个端点之间的任何地方)可能意味着如果您在合理的空闲时间之后尝试发送数据,则连接将不再“起作用”。但是,在尝试发送数据之前,您可能不会发现这一点。

使用Keepalive不仅可以减少连接中断的可能性,还可以使您更快地发现断开的连接。


啊! 您在这里增加了一个要点,那就是您还必须考虑可能会妨碍连接操作的中间因素,例如NAT路由器等...
Kevin Boyd

4
这是一个好点,也很好地提醒了我们,除了我们直接实现自己的目标之外,还有更多要记住的地方。还有,旅鼠!
马修·沙利

请注意,共享p2p文件会占用大量端口并产生大量僵尸连接,从而使NAT更有可能需要修剪空闲连接。
Artelius

4
TCP连接不一定由4个元素标识:src ip,src端口,dest ip,dest端口。因此,只要目标ip不同,就可以重用相同的外部(源)端口。
Dan Berindei 2010年

1
哦,是的,你是对的。我认为,真正的原因是由于内存限制和查找时间,NAT具有固定大小的开放连接表。
Artelius


1

在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反射检索。


0

对于Windows,根据Microsoft文档

  • 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,无法更改
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.