我有一个基于web的应用程序和一个客户端,都是用Java编写的。值得一提的是,客户端和服务器都在Windows上。客户端通过Apache HttpClient发出HTTP GET请求。服务器会阻塞最多一分钟,如果客户端在此期间没有收到任何消息,则服务器返回HTTP 204无内容。否则,只要有消息准备好发送给客户端,就会立即返回HTTP 200 OK的响应。
以下是令我感到困惑的事情:对于特定子集的客户端(总是网络连接不稳定),偶尔会出现这样的情况:客户端发出GET请求,服务器接收并处理GET请求,但客户端却一直处于等待状态。启用客户端的调试日志后,我发现HttpClient仍在等待响应的第一行。
服务器上没有抛出任何异常,至少没有任何日志记录,无论是Tomcat还是我的Web应用程序。根据调试日志显示,服务器成功地向客户端发送了响应。然而,客户端没有收到任何东西。客户端在HttpClient.executeMethod中无限期地挂起。这在会话超时后变得明显,并且客户端采取导致另一个线程发出HTTP POST的操作时。当然,POST会失败,因为会话已过期。在某些情况下,会话过期后到客户端发出POST并发现此事实之间可能已经过去了几个小时。在这整个时间里,executeMethod
仍在等待HTTP响应行。
当我使用WireShark查看实际上正在发生的情况时,就不会出现这种故障。也就是说,在特定的客户端上,如果同时在两端运行WireShark,那么这些客户端将可以连续运行14个小时以上而不会出现故障。
大家有没有遇到过这种情况?这是什么原因造成的呢?我认为 TCP/IP 可以保证即使在短暂的网络故障中也能确保数据包的传递。如果我设置了 SO_TIMEOUT 并在超时后立即重试请求,那么重试总是成功的。(当然,我首先需要中止超时的请求并释放连接以确保使用新的套接字。)
有什么想法吗?有什么办法可以让 Java 或者 Windows 的注册表设置更加积极地进行丢失数据包的 TCP/IP 重试吗?