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

时间:2009-09-26 02:09:21

标签: java sockets http tcp keep-alive

我听说过HTTP keep-alive但是现在我想打开一个与远程服务器的套接字连接 现在这个套接字连接是否会永远保持打开状态,或者是否存在与之相关的超时限制,类似于HTTP keep-alive?

8 个答案:

答案 0 :(得分:73)

  

现在这个套接字连接是否会永远保持打开状态,或者是否存在与之关联的超时限制,类似于HTTP keep-alive?

简短的回答是,,超时并通过TCP Keep-Alive强制执行。

如果您想配置Keep-Alive超时,请参阅"更改TCP超时"以下部分。

简介

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

然而,在此之前,双方将无限期地保持其套接字开放。这使得一方可能有意或由于某些错误而关闭其套接字,而无需通过RST通知另一端。为了检测这种情况并关闭陈旧连接,使用TCP Keep Alive进程。

Keep-Alive Process

有三种可配置属性可确定Keep-Alives的工作方式。在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步
  4. 默认情况下,在大多数操作系统上启用此过程,因此,如果另一端无响应2小时11分钟(7200秒+ 75 * 9秒),则会定期修剪死TCP连接。

    陷阱

    2小时默认

    由于该过程在默认情况下连接空闲两小时后才开始,因此过时的TCP连接可能会在被修剪之前停留很长时间。这对于数据库连接等昂贵的连接尤其有害。

    Keep-Alive是可选的

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

      

    执行者可能包括" keep-alives"在他们的TCP实现中,   虽然这种做法并未得到普遍接受。如果保持活着   包含,应用程序必须能够为每个打开或关闭它们   TCP连接,它们必须默认关闭。

         

    ...

         

    非常   重要的是要记住不包含数据的ACK段   由TCP可靠传输。

    原因是Keep-Alive数据包不包含任何数据,并且不是绝对必要的,如果过度使用,可能会堵塞互联网的管道。

    在实践中,我的经验是,随着带宽变得越来越便宜,这种担忧随着时间的推移逐渐减少;因此,通常不会丢弃Keep-Alive数据包。 Amazon EC2 documentation例如对Keep-Alive进行间接认可,因此,如果您使用AWS进行托管,您可能会安全地依赖Keep-Alive,但您的里程可能会有所不同。

    更改TCP超时

    每个插座

    不幸的是,由于TCP连接是在操作系统级别进行管理的,因此Java不支持在每个套接字级别配置超时,例如在java.net.Socket中。我发现有一些尝试 3 使用Java Native Interface(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
    

    值得注意的是,Mac OS X以毫秒为单位定义keepidlekeepintvl,而不是使用秒的Linux。

    可以使用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。这个数据包通常被称为&#34; Keep-Alive&#34;数据包,但在TCP规范中,它只是一个常规的ACK数据包。 Wireshark等应用程序可以将其标记为“保持活跃”和#34;数据包通过元数据分析它包含的序列和确认号,参考插座上的前面的通信。

    <子> 3。我从基本Google搜索中找到的一些示例包括lucwilliams/JavaLinuxNetflonatel/libdontdie

答案 1 :(得分:64)

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

也就是说,在没有实际发送数据的情况下检测断开连接(断路,如路由器死亡等,而不是关闭)非常困难,因此大多数应用程序每隔一段时间就会做一些ping / pong反应确保连接仍然存在。

答案 2 :(得分:52)

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

Java Socket API通过setKeepAlivegetKeepAlive方法向应用程序公开“保持活动”状态。

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

由于没有数据发送,SO_KEEPALIVE只能测试网络连接的活跃程度,而不能测试套接字连接的服务的活跃程度。要测试后者,您需要实现一些涉及向服务器发送消息并获得响应的内容。

答案 3 :(得分:32)

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

这是来自TCP规范,

只有在间隔内没有收到连接的数据或确认数据包时,才能发送保持活动的数据包。这个间隔必须是可配置的,必须默认不少于两个小时。

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

答案 4 :(得分:22)

如果你是伪装NAT的背后(如今大多数家庭用户都是这样),那么外部端口池有限,这些端口必须在TCP连接之间共享。因此,如果在一段时间内没有发送数据,伪装NAT往往会假设连接已终止。

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

使用Keepalive 可以减少连接在某个地方被中断的可能性,并且还可以让您更快地找到断开的连接。

答案 5 :(得分:4)

以下是一些关于keepalive的补充文献,它以更精细的细节解释了它。

http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO

由于Java不允许您控制实际的保持活动时间,因此如果您使用的是Linux内核(或基于proc的操作系统),则可以使用这些示例来更改它们。

答案 6 :(得分:0)

在JAVA套接字中-TCP连接是在操作系统级别上管理的,java.net.Socket不提供任何内置功能来为每个套接字级别的keepalive数据包设置超时。但是我们可以为java套接字启用keepalive选项,但是默认情况下,在过时的tcp连接之后,它需要2小时11分钟(7200秒)才能处理。在吹扫之前,这会导致连接很长一段时间。因此,我们找到了一种使用Java本机接口(JNI)的解决方案,该解决方案调用本机代码(c ++)来配置这些选项。

**** Windows OS ****

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

答案 7 :(得分:0)

对于Windows,Microsoft docs

  • 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,无法更改