2011-12-06 38 views
4

我使用Apache HttpClient 4.1.2將壓縮的二進制數據(序列化的Java對象)張貼到服務器。服務器響應後Apache HttpClient超時異常

即使服務器已正確響應並在自己的日誌記錄中記錄了「200」響應,有時(20%的時間)客戶端在收到響應時會超時,

的事件的序列是:

  • 客戶端的POST數據到服務器(T0)。
  • 服務器記錄數據接收(T2,即T + 2秒)。
  • 服務器處理數據。
  • 服務器日誌成功完成處理(T45)。
  • 服務器訪問日誌顯示以「200」狀態(T46)出現已完成的響應。
  • 客戶端塊讀取響應頭。
  • 客戶端超時(T1800,即POST請求後30分鐘,這是我使用的標準超時)。

服務器返回的響應主體是一個很小的,比如5個字節或更少的純文本字符串,例如, 「好」。

這裏可能會發生什麼?如果服務器沒有響應,我可以理解超時;但是服務器已經做出了響應,並且在客戶超時之前及時記錄了正確的響應。客戶似乎「試圖」讀取響應,但會阻止並最終超時。

客戶端在Windows XP機器上運行;服務器是Ubuntu。兩者都運行Java 6(現在1.6.29)。

我爲每個請求創建一個新的DefaultHttpClient對象,並在每次請求後關閉它(並適當地釋放其他資源)。

客戶端在請求成功完成後消耗和處置響應實體主體,但我們還沒有到達那一點 - 超時發生在httpclient.execute(方法)調用的上下文中。

堆棧跟蹤:

java.net.SocketTimeoutException: Read timed out 
    at java.net.SocketInputStream.socketRead0(Native Method) 
    at java.net.SocketInputStream.read(Unknown Source) 
    at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:149) 
    at org.apache.http.impl.io.SocketInputBuffer.fillBuffer(SocketInputBuffer.java:110) 
    at org.apache.http.impl.io.AbstractSessionInputBuffer.readLine(AbstractSessionInputBuffer.java:264) 
    at org.apache.http.impl.conn.LoggingSessionInputBuffer.readLine(LoggingSessionInputBuffer.java:115) 
    at org.apache.http.impl.conn.DefaultResponseParser.parseHead(DefaultResponseParser.java:98) 
    at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:252) 
    at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:281) 
    at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:247) 
    at org.apache.http.impl.conn.AbstractClientConnAdapter.receiveResponseHeader(AbstractClientConnAdapter.java:219) 
    at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:298) 
    at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125) 
    at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:645) 
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:464) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820) 
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754) 
    at foo.StreamerClient.sendRequest(StreamerClient.java:312) 
    at foo.StreamerClient.compressAndPostBinaryDataToFooServer(StreamerClient.java:287) 
    at foo.StreamerClient.compressAndPostObjectsToFooServer(StreamerClient.java:238) 

下面是一個成功的請求線級別的記錄。與不成功的請求唯一的區別是,在記錄二進制數據後,不成功的請求會停止,並且半小時後再次彈出並記錄超時。

[12-06 14:07:22.359][scheduler-3] D DefaultClientConnection Sending request: POST /foo/bar HTTP/1.1 
[12-06 14:07:22.359][scheduler-3] D wire      >> "POST /foo/bar HTTP/1.1[\r][\n]" 
[12-06 14:07:22.359][scheduler-3] D wire      >> "Accept-Encoding: gzip,deflate[\r][\n]" 
[12-06 14:07:22.359][scheduler-3] D wire      >> "Content-Type: application/octet-stream[\r][\n]" 
[12-06 14:07:22.359][scheduler-3] D wire      >> "Content-Length: 401[\r][\n]" 
[12-06 14:07:22.359][scheduler-3] D wire      >> "Host: foo.com[\r][\n]" 
[12-06 14:07:22.359][scheduler-3] D wire      >> "Connection: Keep-Alive[\r][\n]" 
[12-06 14:07:22.359][scheduler-3] D wire      >> "User-Agent: Apache-HttpClient/4.1.2 (java 1.5)[\r][\n]" 
[12-06 14:07:22.359][scheduler-3] D wire      >> "Authorization: Basic fobar[\r][\n]" 
[12-06 14:07:22.359][scheduler-3] D wire      >> "[\r][\n]" 
[12-06 14:07:22.359][scheduler-3] D wire      >> "[several lines of binary data]" 
[12-06 14:07:24.265][scheduler-3] D wire      << "HTTP/1.1 200 OK[\r][\n]" 
[12-06 14:07:24.265][scheduler-3] D wire      << "Date: Tue, 06 Dec 2011 03:07:23 GMT[\r][\n]" 
[12-06 14:07:24.265][scheduler-3] D wire      << "Content-Type: text/plain;charset=ISO-8859-1[\r][\n]" 
[12-06 14:07:24.265][scheduler-3] D wire      << "Content-Length: 2[\r][\n]" 
[12-06 14:07:24.265][scheduler-3] D wire      << "Connection: close[\r][\n]" 
[12-06 14:07:24.265][scheduler-3] D wire      << "[\r][\n]" 

謝謝。

回答

2

我注意到,迴應說

Content-Length: 2 

但我沒有看到[\r][\n]關閉空行不應被算作內容後的任何內容。我認爲這是你的問題。服務器應該說Content-Length: 0或者它沒有適當地沖洗它的緩衝區或其他東西。

此外,在報頭中的服務器是在說:

Connection: close 

對服務器關閉了連接或在客戶端仍連接?如果服務器沒有關閉,那麼它會以某種方式卡住。

希望這會有所幫助。

+0

感謝您的回覆。我所包含的迴應是成功的。 (在記錄任何入站有線流量之前,不成功的超時)。我也注意到Content-Length:2的業務,但在這種情況下,請求和響應已經成功,所以它必須做正確的事情;如果沒有其他,服務器和客戶端就如何處理響應達成一致。 Connection:close是,我敢肯定,只是HTTP響應的標準最後一行,類似於腳本語言中的「EOF」。 – user1082373

+0

不,「Connection:close」表示在響應之後,服務器應該關閉連接。它是這樣做的嗎?如果你看看服務器(或者netstat -an),你還能看到連接嗎?請參閱:http://docs.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html – Gray

+0

它既來自客戶端,也來自服務器。客戶端可以請求服務器在響應後關閉連接。如果服務器顯示「Connection:close」,那麼最好關閉連接。如果連接未關閉,則服務器端出現問題。 – Gray

相關問題