为什么DefaultHttpClient通过半closures套接字发送数据?

我使用Android(2.3.x)上的ThreadSafeClientConnManager DefaultHttpClient发送HTTP请求到我的REST服务器(embedded式Jetty)。

在大约200秒的空闲时间之后,服务器用[FIN]closuresTCP连接。 Android客户端使用[ACK]进行响应。 这应该并且确实将套接字置于半closures状态(服务器仍在监听,但不能发送数据)。

我希望当客户端尝试再次使用该连接(通过HttpClient.execute )时, DefaultHttpClient会检测到半closures状态,closures客户端的套接字(因此发送它[FIN / ACK]来结束closures) ,并为请求打开一个新的连接。 但是,这是一个问题。

而是通过半封闭套接字发送新的HTTP请求。 只有在发送完成后,客户端检测到半closures状态并closures套接字(将[FIN]发送到服务器)。 当然,服务器不能响应请求(它已经发送了它的[FIN]),所以客户端认为请求失败,并通过一个新的套接字/连接自动重试。

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

有想法该怎么解决这个吗? (我的服务器用第二个副本做了正确的事情,但我很烦恼有效负载传输了两次。)

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

Solutions Collecting From Web of "为什么DefaultHttpClient通过半closures套接字发送数据?"

这是Java中阻塞I / O的一般限制。 除了尝试从套接字读取以外,根本没有办法找出对端是否已经closures了连接。 Apache HttpClient通过使用如此陈旧的连接检查来解决这个问题,这本质上是一个非常简短的读取操作。 但是,检查可以并经常被禁用。 事实上,由于检查引入了额外的延迟,通常会禁用它。 我不知道在这方面,Android的HttpClient版本的行为究竟如何,但你可以尝试使用适当的configuration参数明确地启用检查。

对这个问题的更好的解决scheme可能是从连接池中删除在一段时间不活动之后在特定时间段(比如说150秒)空闲的连接。

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