【问题标题】:TCP keep-alive gets involved after TCP zero-window and closes the connection erroneouslyTCP keep-alive 在 TCP 零窗口后参与并错误关闭连接
【发布时间】:2016-02-10 17:09:14
【问题描述】:

我们发现这种模式经常发生在两个通过 TCP 连接传输数据的 RHEL 6 机器之间。客户端发出 TCP 窗口已满,0.2 秒后客户端发送 TCP Keep-Alives,服务器以看起来正确形状的响应对其进行响应。然而,客户端对此并不满意,并继续发送 TCP Keep-Alives,直到它最终在将近 9 秒后以 RST 关闭连接。

尽管 RHEL 盒子具有默认的 TCP Keep-Alive 配置:

net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75

...它声明这应该只发生在 2 小时的沉默之前。我是否读错了我的 PCAP(可根据要求提供相关数据包)?

下面是 Wireshark 的模式截图,中间是我自己的数据包注释。

【问题讨论】:

  • 这些确实是窗口探针。屏幕截图一如既往地难以辨认。
  • 你能扩展你的断言吗?两次单击屏幕截图使其清晰易读。如果需要,可提供 PCAP 提取物。
  • 两次点击并没有让我看清。我认为没有必要进一步扩展。

标签: tcp wireshark keep-alive


【解决方案1】:

实际上,这些“keep-alive”数据包并不用于 TCP keep-alive!它们用于窗口大小更新检测。

Wireshark 将它们视为 keep-alive 数据包,只是因为这些数据包看起来像 keep-alive 数据包。

TCP 保持活动数据包只是一个 ACK​​,其序列号设置为比连接的当前序列号小一。

(我们假设ip 10.120.67.113是指主机A,10.120.67.132是指主机B。)在包No.249511中,A确认seq 24507484。在下一个包(No.249512)中,B发送seq 24507483( 24507484-1)。

为什么会有这么多“keep-alive”数据包,它们是用来做什么的?

A向B发送数据,B回复零窗口大小告诉A他暂时不能再接收数据了。为了确保 A 知道 B 何时可以再次接收数据,A 用persistence timer 一次又一次地向 B 发送“keep-alive”数据包,B 用他的窗口大小信息回复 A(在我们的例子中,B 的窗口大小有一直为零)。

并且在计算持续计时器时使用正常的 TCP 指数退避。所以我们可以看到A在0.2s后发送了它的第一个“keep-alive”数据包,在0.4s后发送了第二个数据包,在0.8后发送了第三个数据包,在1.6s后发送了第四个......

此现象与TCP流控有关。

【讨论】:

    【解决方案2】:

    来自客户端的数据包中的源IP地址和目标IP地址与响应数据包中的目标IP地址和源IP地址不匹配,这表明盒子之间有一些设备正在执行NAT。了解数据包的捕获位置也很重要。客户端本身的数据包捕获可能有助于理解问题。

    请注意,如果客户端在两个小时或更长时间内没有收到数据包,则可以生成 TCP keepalive。根据 RFC 1122,如果客户端没有收到来自对等方的 keepalive 响应,它会重试 keepalive。在连续重试失败后,它最终会断开连接。

    NAT 设备通常会实施连接缓存来维护正在进行的连接的状态。如果连接的大小达到限制,NAT 设备会丢弃旧连接以便为新连接提供服务。这也可能导致这种情况。

    给定的数据包捕获表明数据包没有到达客户端的可能性很高,因此在客户端计算机上捕获数据包会很有帮助。

    【讨论】:

      【解决方案3】:

      我对跟踪的阅读略有不同: 发送方发送的数据超出接收方的处理能力并获得零窗口响应 发送者发送窗口探测(不是keepalives,它很快就会这样做)并且应用程序在10秒后没有进展就放弃并关闭连接,重置表明TCP发送缓冲区中有数据未决。 如果应用程序使用大块大小写入套接字,它可能在 tcpdump 中看到的 10 秒以上没有任何进展。

      如果这是直接连接(无代理等),最可能的原因是接收停止接收(或比发送方和数据传输慢)

      【讨论】:

        【解决方案4】:

        在我看来,数据包编号 249522 引发了 10.120.67.113 上的应用程序以中止连接。所有窗口探测器都从 .132 获得零窗口响应(没有有效负载),然后 .132 发送(未经请求的)数据包 249522 63 字节(仍然显示 0 窗口)。 PSH 标志表明这 63 个字节是应用程序在 .132 上写入的全部数据。然后 .113 在同一毫秒内以 RST 响应。我想不出为什么 TCP 堆栈会在收到数据后立即发送 RST(序列号是正确的)。在我看来,基于 .132 发送的 63 字节消息,几乎可以肯定 .113 上的应用决定放弃。

        【讨论】:

          猜你喜欢
          • 2017-02-19
          • 2016-09-07
          • 2013-03-25
          • 1970-01-01
          • 2022-01-17
          • 1970-01-01
          • 2014-07-25
          • 2016-03-20
          • 1970-01-01
          相关资源
          最近更新 更多