为什么DefaultHttpClient通过半封闭的套接字发送数据?

时间:2012-06-27 04:17:28

标签: java android tcp apache-httpclient-4.x

我在Android(2.3.x)上使用DefaultHttpClientThreadSafeClientConnManager将HTTP请求发送到我的REST服务器(嵌入式Jetty)。

在空闲时间约200秒后,服务器用[FIN]关闭TCP连接。 Android客户端以[ACK]响应。这应该并确实使套接字处于半闭状态(服务器仍在监听,但无法发送数据)。

我希望当客户端再次尝试使用该连接时(通过HttpClient.execute),DefaultHttpClient将检测到半关闭状态,关闭客户端上的套接字(从而发送它的[ FIN / ACK]完成关闭),并为请求打开一个新连接。但是,有一点问题。

相反,它通过半封闭套接字发送新的HTTP请求。只有在发送后才检测到半闭状态,并且套接字在客户端关闭([FIN]发送到服务器)。当然,服务器无法响应请求(它已经发送了它的[FIN]),因此客户端认为请求失败并通过新的套接字/连接自动重试。

最终结果是服务器查看并处理请求的两个副本。

有关如何解决此问题的任何想法? (我的服务器使用第二个副本执行了正确的操作,但我很恼火有效负载会被传输两次。)

在第一次尝试写入新的HTTP数据包时,DefaultHttpClient是否应该检测到套接字是否已关闭,请立即关闭该套接字并启动一个新套接字?在服务器发送[FIN]后几分钟内,如何在套接字上发送新的HTTP请求,我感到很困惑。

1 个答案:

答案 0 :(得分:5)

这是Java中阻塞I / O的一般限制。除了尝试从套接字读取之外,根本无法确定对端是否具有闭合连接。 Apache HttpClient通过采用如此陈旧的连接检查来解决这个问题,这种检查本质上是一个非常简短的读取操作。但是,检查可以并且经常被禁用。实际上,由于检查引入的额外延迟,通常建议将其禁用。我不知道Android附带的HttpClient版本究竟在这方面表现如何,但您可以尝试使用适当的配置参数明确启用检查。

此问题的更好解决方案可能是在一段时间不活动后,从连接池中驱逐在特定时间段(例如150秒)内空闲的连接。

http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d5e652