2012-06-27 45 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

相關問題