java - 什么会导致 TCP/IP 在不断开连接的情况下丢弃数据包?

标签 java http tomcat tcp

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

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

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

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

有没有人遇到过这样的事情?究竟是什么导致了它?我认为即使出现短期网络故障,TCP/IP 也能保证数据包传送。如果我设置 SO_TIMEOUT 并在超时时立即重试请求,则重试总是成功。 (当然,我先abort超时请求,释放连接,保证使用新的socket。)

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

最佳答案

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

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

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

如果我是你,我会继续使用 wireshark 监控所有端点,直到问题再次出现。它很可能会。但是,听起来您最终会发现的就是您已经提到的 - 易碎的硬件。如果修复不稳定的硬件是不可能的,您可能需要构建额外的应用程序级超时并重试以尝试处理软件中的问题。听起来你开始走这条路了。

关于java - 什么会导致 TCP/IP 在不断开连接的情况下丢弃数据包?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/787415/

相关文章:

javascript - 带有 HTTP 请求 header 的 Parse.Cloud.httpRequest 调用

http - Nmap 卡住在 NSE 计时阶段

tomcat - 在 spring REST 应用程序中引用来自 tomcat 的依赖 jar

java - 从 war 中提取 SymmetricDS 引擎

windows - 我们如何在同一台 Windows 7 机器上运行 Apache Http Server 的两个实例

eclipse - 无法将 Eclipse EE 与 Tomcat 集成

java - 发送电子邮件功能出错

java - 为什么 MongoDB Java 驱动程序在条件中使用随机数生成器?

java - 优雅地为 ExecutorServices 实现队列长度指示器

java - Android 中的@Override 注解