【问题标题】:timeout in a TCP connection with no exchange of data没有数据交换的 TCP 连接超时
【发布时间】:2018-04-18 09:17:21
【问题描述】:

我有一个用于 Linux 中 TCP 客户端和服务器的 C/C++ 应用程序。

假设在 TCP 连接到位后,服务器和客户端都没有在很长一段时间内发送任何数据。他们甚至不会互相发送任何心跳。

通过 TCP 协议,连接应该存在多长时间?

连接是否因不活动而断开?

如果是这样,是否有任何套接字选项可以指定或定义任何类型的超时行为?

【问题讨论】:

    标签: c++ sockets networking tcp


    【解决方案1】:

    恐怕唯一明智的答案应该是视情况而定

    一个 TCP 连接可以在两端之间使用多个中间中继。每个组件(读取每个端和每个中继)都可以有自己的策略来关闭不活动的连接。

    一个常见的解决方法是使用keepalive 作为一个可选 TCP 功能。当连接空闲超过定义的超时时间时,它由一端发送的空包组成。对等方应以 ACK 应答,即使它不支持 keepalive 扩展,这足以在 TCP 级别保持连接处于活动状态。

    例如,在 Linux 中,keepalive 可以在内核级别设置,并且对于所有新的 TCP 连接都将处于活动状态。这可能是个坏主意,因为默认情况下 keepalive 是关闭的,以避免网络开销。从参考页面:

    涉及keepalive的程序使用三个用户驱动的变量:

    tcp_keepalive_time

    最后一个数据包发送(简单的ACKs不被认为是数据)和第一个keepalive探测之间的间隔;在连接被标记为需要保持连接后,不再使用此计数器 tcp_keepalive_intvl

    后续keepalive探测之间的间隔,无论连接在此期间交换了什么

    tcp_keepalive_probes

    在考虑连接失效并通知应用层之前要发送的未确认探测数

    它们可以设置为例如sysctl(8):

     # sysctl -w \
     > net.ipv4.tcp_keepalive_time=600 \
     > net.ipv4.tcp_keepalive_intvl=60 \
     > net.ipv4.tcp_keepalive_probes=20
     net.ipv4.tcp_keepalive_time = 600
     net.ipv4.tcp_keepalive_intvl = 60
     net.ipv4.tcp_keepalive_probes = 20
    

    也可以使用setsockopt为应用程序级别的某些连接设置它:

      /* Set the option active */
      int optval = 1;
      socklen_t optlen = sizeof(optval);
      if(setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {
         perror("setsockopt()");
         close(s);
         exit(EXIT_FAILURE);
      }
    

    【讨论】:

    • '对端应该用一个 ACK​​ 来回答,即使它不支持 keepalive 扩展'是没有意义的。它不能支持keepalive扩展,因为它只是发送一个带有过期序列号的空包,根据RFC 793,它必须由一个带有当前预期序列号的ACK来回答。
    • 所以如果连接保持活动状态..为什么所有服务器和客户端都会互相发送 HEARTBEAT?是否只是为了节省服务器端的资源(如果客户端出现故障,服务器可能会释放 pc 资源)。还是套接字有其他问题?
    • @AbruzzoForteeGentile 服务器的问题是区分一个活跃但当前沉默的客户端;和一个已经崩溃、丢失网络连接等的客户端。服务器需要恢复资源,否则一个简单的拒绝服务攻击将是连接然后丢弃物理层而不关闭 TCP/IP 连接。服务器会很快耗尽资源。
    • @AbruzzoForteeGentile:TCP keepalive 默认关闭,在某些系统上可能不可用。因此,在更高的协议级别添加该功能是有意义的。
    【解决方案2】:

    通过 TCP 协议,连接应该存在多长时间?

    永远。

    连接是否因不活动而断开?

    没有。

    如果是这样,是否有任何套接字选项可以指定或定义任何类型的超时行为?

    支持 SO_RCVTIMEO。这为recv() 方法和朋友提供了读取超时。

    【讨论】:

    • 您能否详细说明 SO_RCVTIMEO 选项。
    【解决方案3】:

    使用选择? Select - Linux manuel page

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-16
      相关资源
      最近更新 更多