【问题标题】:What can cause TCP/IP to drop packets without dropping the connection?什么会导致 TCP/IP 丢弃数据包而不丢弃连接?
【发布时间】:2010-10-21 16:57:04
【问题描述】:

我有一个基于 Web 的应用程序和一个客户端,它们都是用 Java 编写的。值得一提的是,客户端和服务器都在 Windows 上。客户端通过Apache HttpClient 发出HTTP GET。服务器最多阻塞一分钟,如果在那一分钟内没有消息到达客户端,则服务器返回 HTTP 204 No Content。否则,一旦为客户端准备好消息,就会返回带有 HTTP 200 OK 的正文。

这让我感到困惑:间歇性地对于特定的客户端子集——总是具有明显不稳定的网络连接的客户端——客户端发出 GET,服务器接收并处理 GET,但是客户永远坐着。为客户端启用调试日志,我看到 HttpClient 仍在等待响应的第一行。

服务器上没有抛出异常,至少没有任何地方记录,不是由Tomcat,不是由我的webapp。根据调试日志,服务器成功响应客户端的各种迹象。但是,客户没有收到任何东西的迹象。客户端在HttpClient.executeMethod 中无限期挂起。这在会话超时并且客户端采取导致另一个线程发出 HTTP POST 的操作后变得很明显。当然,POST 失败是因为会话已过期。在某些情况下,从会话到期到客户端发出 POST 并发现这一事实之间已经过去了 小时。在整个过程中,executeMethod 仍在等待 HTTP 响应行。

当我使用 WireShark 查看线路级别的实际情况时,不会发生此故障。也就是说,对于特定客户端,此故障将在几个小时内发生,但当 WireShark 在两端运行时,这些相同的客户端将运行一夜,14 小时,而不会出现故障。

有没有其他人遇到过这样的事情?到底是什么原因造成的?我认为即使在短期网络故障中,TCP/IP 也能保证数据包的传递。如果我设置了 SO_TIMEOUT 并在超时时立即重试请求,重试总是成功的。 (当然,我先abort这个超时请求,然后释放连接,保证会使用新的socket。)

想法?想法?是否有一些适用于 Java 的 TCP/IP 设置或 Windows 中的注册表设置可以对丢失的数据包启用更积极的 TCP/IP 重试?

【问题讨论】:

  • 听起来观察正在改变结果 -> Heisenbug -> 线程有问题。在这种情况下,听起来有人太(我会把钱放在 HttpClient 上)并因此而陷入僵局。您可能遇到了 HttpClient 本身的错误,希望其他人可以提供更多帮助并帮助您解决此问题。

标签: java http tomcat tcp


【解决方案1】:

如果您使用长时间运行的 GET,您应该在客户端超时两倍于服务器超时,正如您所发现的那样。

在客户端发送消息并期望响应的 TCP 上,如果服务器崩溃并重新启动(让我们举例说明),那么客户端仍将在套接字上等待从服务器但服务器不再在该套接字上侦听。

客户端只有在向该套接字发送更多数据时才会发现该套接字在服务器端已关闭,并且服务器拒绝此新数据并关闭该套接字。

这就是为什么您应该在请求上设置客户端超时。

但是由于您的服务器没有崩溃,如果服务器是多线程的,并且该客户端的线程套接字关闭,但当时(持续时间分钟)客户端连接中断,那么结束套接字握手我会丢失了,并且由于您没有从客户端向服务器发送更多数据,因此您的客户端再次挂起。这将与您的剥落连接观察有关。

【讨论】:

    【解决方案2】:

    您确定服务器已成功将响应发送给似乎失败的客户端吗?我的意思是服务器已经发送了响应,并且客户端已经将该响应返回给服务器。您应该在服务器端使用wireshark 看到这一点。如果您确定这发生在服务器端并且客户端仍然没有看到任何东西,您需要从服务器进一步查看链。是否涉及任何代理/反向代理服务器或 NAT?

    TCP 传输被认为是一种可靠的协议,但它不保证传送。您的操作系统的 TCP/IP 堆栈将非常努力地使用 TCP 重新传输将数据包发送到另一端。如果发生这种情况,您应该在服务器端的 wireshark 中看到这些。如果您看到过多的 TCP 重新传输,通常是网络基础设施问题 - 即硬件/接口错误或配置错误。 TCP 重传适用于短暂的网络中断,但在中断时间较长的网络上表现不佳。这是因为 TCP/IP 堆栈只会在计时器到期后发送重传。该计时器通常在每次不成功的重传后加倍。这是为了避免重传淹没已经存在问题的网络而设计的。正如您可能想象的那样,这通常会导致应用程序出现各种超时问题。

    根据您的网络拓扑,您可能还需要将探针/wireshark/tcpdump 放置在网络中的其他中间位置。这可能需要一些时间才能找出数据包的去向。

    如果我是你,我会一直使用wireshark 进行监控,直到问题再次出现。它很可能会。但是,听起来您最终会发现的是您已经提到的东西——片状硬件。如果修复脆弱的硬件是不可能的,您可能只需要构建额外的应用程序级超时并重试以尝试在软件中处理问题。听起来你开始走这条路了。

    【讨论】:

    • 当它发生时,我可以从适当的调试中得知我的 Web 应用程序认为它已经响应。我没有在 Tomcat (6.x) 本身中启用任何调试,以查看它是否认为它已经完成了响应。 Tomcat 的日志、Apache HTTPD 的日志和 mod_jk 的日志都没有任何投诉。易碎的硬件完全不在我的掌控之中……在某些情况下,人们正在访问公共互联网。
    • 硬信息是无可替代的。 Wireshark 会告诉你谁在说话,谁不是。
    【解决方案3】:

    如果您丢失数据,很可能是由于软件错误,无论是读取库还是写入库。

    【讨论】:

      【解决方案4】:

      忘记刷新或关闭主机端的套接字可能会间歇性地对短响应产生这种影响,具体取决于时间,这可能会受到任何监控机制的影响。

      特别是忘记关闭将使套接字悬空,直到 GC 开始回收它并调用 finalize()。

      【讨论】:

        【解决方案5】:

        我还没有看到这个本身,但我看到过大型 UDP 数据报的类似问题,导致 IP 分段,导致拥塞并最终丢弃以太网帧。由于这是 TCP/IP,我不认为 IP 碎片是一个大问题,因为它是基于流的协议。

        我要注意的一件事是 TCP 不保证交付!它不能。它保证的是,如果您发送 byte A 后跟 byte B,那么在收到 之前,您将永远不会收到 byte B >字节A.

        话虽如此,我会将客户端机器和监控机器连接到集线器。在监控机器上运行 Wireshark,你应该可以看到发生了什么。我确实遇到了与 HTTP 请求之间的空白处理和不正确的 HTTP 块大小有关的问题。这两个问题都是由手写的 HTTP 堆栈引起的,因此只有在使用易碎堆栈时才会出现问题。

        【讨论】:

          【解决方案6】:

          这些计算机是否安装了病毒/恶意软件?使用 wireshark 会安装 winpcap (http://www.winpcap.org/),它可能会覆盖恶意软件所做的更改(或者恶意软件可能只是检测到它正在被监控,而不是尝试任何可疑的事情)。

          【讨论】:

          • 我没有考虑过这一点,但它当然是遥不可及的。因为我只在网络连接不稳定的客户端上看到这种情况,所以到目前为止,我一直认为不稳定本身就是原因。
          • 恶意软件是远程可能的,但不太可能。使用你已经知道的东西 - 片状。
          猜你喜欢
          • 1970-01-01
          • 2018-02-19
          • 2011-12-19
          • 1970-01-01
          • 1970-01-01
          • 2012-06-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多