我有一个基于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响应行。
executeMethod
当我使用WireShark来查看导线级别的实际情况时,不会发生此故障。也就是说,对于特定客户端,此故障将在几个小时内发生,但是当WireShark在两端运行时,这些相同的客户端将在整整14小时内运行一整夜,而不会出现故障。
有没有其他人遇到过这样的事情?到底是什么引起的?我认为TCP / IP即使在短期网络故障中也能保证数据包的传递。如果我设置了SO_TIMEOUT并在超时后立即重试该请求,则重试始终会成功。(当然,我首先中止超时请求并释放连接以确保将使用新的套接字。)
有什么想法吗?有想法吗?是否有Java可用的某些TCP / IP设置或Windows中的注册表设置,可以对丢失的数据包进行更积极的TCP / IP重试?
您是否完全确定服务器已成功将响应发送给似乎失败的客户端?我的意思是服务器已经发送了响应,客户端已经将该响应确认回服务器。您应该在服务器端使用Wireshark看到它。如果确定这是在服务器端发生的,并且客户端仍然看不到任何东西,则需要从服务器上进一步查找链。是否有任何代理/反向代理服务器或NAT?
TCP传输被认为是可靠的协议,但不能保证传递。您的操作系统的TCP / IP堆栈将尽力使用TCP重传将数据包发送到另一端。如果发生这种情况,您应该在服务器端的Wireshark中看到它们。如果看到过多的TCP重传,通常是网络基础结构问题- 即硬件/接口错误或配置错误。TCP重传对于短暂的网络中断非常有效,但在中断时间较长的网络上效果较差。这是因为TCP / IP堆栈仅在计时器到期后才发送重传。每次重传失败后,此计时器通常都会加倍。这是通过设计来避免因重传而使本来就很麻烦的网络泛滥。如您所想,
根据您的网络拓扑,您可能还需要将探针/ wireshark / tcpdump放置在网络中的其他中间位置。这可能需要一些时间来找出数据包的去向。
如果您是我,我将始终通过wireshark进行监视,直到问题再次出现。它很可能会。但是,听起来您最终会发现的就是您已经提到的- 片状硬件。如果无法修复不稳定的硬件,则可能仅需要构建额外的应用程序级别超时并重试,以尝试在软件中解决问题。听起来您开始走这条路了。