11

I'm using DefaultHttpClient with a ThreadSafeClientConnManager on Android (2.3.x) to send HTTP requests to a my REST server (embedded Jetty).

After ~200 seconds of idle time, the server closes the TCP connection with a [FIN]. The Android client responds with an [ACK]. This should and does leave the socket in a half-closed state (server is still listening, but can't send data).

I would expect that when the client tries to use that connection again (via HttpClient.execute), DefaultHttpClient would detect the half-closed state, close the socket on the client side (thus sending it's [FIN/ACK] to finalize the close), and open a new connection for the request. But, there's the rub.

Instead, it sends the new HTTP request over the half-closed socket. Only after sending is the half-closed state detected and the socket closed on the client-side (with the [FIN] sent to the server). Of course, the server can't respond to the request (it had already sent its [FIN]), so the client thinks the request failed and automatically retries via a new socket/connection.

The end result is that server sees and processes two copies of the request.

Any ideas on how to fix this? (My server does the correct thing with the second copy, but I'm annoyed that the payload is transmitted twice.)

Shouldn't DefaultHttpClient detect that the socket was closed when it first tries to write the new HTTP packet, close that socket immediately, and start a new one? I'm baffled as to how a new HTTP request is sent on a socket minutes after the server sent a [FIN].

1
  • AndroidHttpClient does the exact same behavior (i.e. a DefaultHttpClient with a ThreadSafeClientConnManager to ensure thread safety)... perhaps you can try using that? I don't know much about the details about how socket connections work, but just a suggestion... Commented Jun 27, 2012 at 4:58

1 Answer 1

7

This is a general limitation of the blocking I/O in Java. There is simply no way of finding out whether or not the opposite endpoint has closed connection other than by attempting to read from the socket. Apache HttpClient works this problem around by employing the so stale connection check which is essentially a very brief read operation. However, the check can and often is disabled. In fact it is often advisable to have it disabled due to extra latency the check introduces. I have no idea how exactly the version of HttpClient shipped with Android behaves in this regard but you could try explicitly enabling the check by using an appropriate config parameter.

A better solution to this problem might be evicting connections from the connection pool that have been idle over a particular period of time (say 150 seconds) after a period of inactivity.

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

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. I have stale connection checks enabled, but the check still isn't performed on Android. It is performed with a standalone, vanilla HttpClient jar. Maybe the Android team really messed around with the HttpClient innards when they imported into the Android repos. I think I'll take the idle connection eviction thread suggestion.
@David B. What Google ships with Adnroid is a fork based on an extremely outdated (pre BETA 4.0) version of Apache HttpClient. It is plausible Google engineers might have removed the stale connection check.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.