2012-06-27 46 views
9

我使用DefaultHttpClient与Android(2.3.x版本)一ThreadSafeClientConnManager发送HTTP请求到我的REST服务器(嵌入式码头)。为什么DefaultHttpClient通过半关闭套接字发送数据?

的空闲时间〜200秒之后,服务器关闭与一个[FIN] TCP连接。 Android客户端以[ACK]响应。这应该并且确实将套接字置于半关闭状态(服务器仍在监听,但不能发送数据)。我期望当客户端尝试再次使用该连接(通过HttpClient.execute)时,DefaultHttpClient会检测到半关闭状态,关闭客户端的套接字(因此发送它[FIN/ACK]来完成关闭),并为请求打开一个新的连接。但是,这是一个问题。

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

最终的结果是,服务器发现和处理该请求的两个副本。

有关如何解决此问题的任何想法? (我的服务器用第二个副本做了正确的事情,但我很烦恼有效负载发送了两次。)

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

+0

'AndroidHttpClient'不完全相同的行为(即一个'DefaultHttpClient'用'ThreadSafeClientConnManager'保证线程安全)......或许你可以尝试使用?我不太了解有关套接字连接如何工作的详细信息,但只是一个建议... –

回答

5

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

一个更好的解决这个问题的可能从已空闲超过特定时间段的连接池逐出连接的一段不活动时间之后(比如说150秒)。

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

+0

谢谢。我启用了陈旧的连接检查,但检查仍然不会在Android上执行。它使用独立的香草HttpClient jar执行。也许Android团队在将它们导入到Android回购站时,真的与HttpClient内部人员搞混了。我想我会采取闲置连接驱逐线程的建议。 –

+1

@David B. Google与Adnroid一起发布的是基于Apache HttpClient的过时版本(pre BETA 4.0)的分支。 Google工程师可能已经删除了陈旧的连接检查,这似乎是合理的。 – oleg

相关问题