Reputation: 129
I have an Android app that sends commands to a robot via HTTP. (The robot server is written in Python using the BaseHttpServer class.) I'm setting up my connection in the app correctly as far as I can tell, but most requests fail to return and if they do there is a very long delay. Here is the initialization code:
private void setupHttpStuff() {
HttpParams params = new BasicHttpParams();
ConnManagerParams.setMaxTotalConnections(params, 10);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(
new Scheme("http", PlainSocketFactory.getSocketFactory(), 1504));
ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
this.HttpClient = new DefaultHttpClient(cm, params);
}
The GET request takes place in an AsyncTask and the code looks like:
HttpContext localContext = new BasicHttpContext();
HttpGet httpGet = new HttpGet(url);
mClient.execute(httpGet, localContext);
Where mClient is a variable shared from the Activity.
By using Log.d messages I've determined that the first two requests work fine but then all subsequent requests (in separate AsyncTasks) hang and never return from execute. I've also tried to manually create a Socket and send a HttpRequest:
Socket socket = new Socket("192.168.1.45", 1504);
HttpParams params = new BasicHttpParams();
DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
conn.bind(socket, params);
HttpRequest request = new BasicHttpRequest("GET", "/");
conn.sendRequestHeader(request);
HttpResponse response = conn.receiveResponseHeader(); // Hangs here
conn.receiveResponseEntity(response);
socket.close();
But this hangs on the conn.receiveResponseHeader() line and the server never sees the request.
The Python server works fine with requests from a browser, just not with my Android app. I've tried this single-threaded as well in the main UI but the same effect occurs.
EDIT
Here is the Python code that causes the problems:
class MyHand(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
qv = parse_qs(get_qs(urlparse(self.path)))
if("method" not in qv):
self.send_nack()
elif(qv["method"][0] == "drive"):
createbot.Drive(int(qv["velocity"][0]), int(qv["radius"][0]))
self.send_ack()
else:
self.send_nack()
def send_ack(self, content_type='text/html'):
self.send_response(200)
self.send_header('Content-type', content_type)
self.end_headers()
def send_nack(self):
self.send_response(500)
self.send_header('Content-type', 'text/html')
self.end_headers()
Upvotes: 1
Views: 493
Reputation: 129
This may be related to keep-alive. Android sends Connection: Keep-Alive and Python sends back a Connection: close. I've looked at the HTTP headers that are being sent from Firefox and HttpClient and there is no difference (other than Firefox sending some additional Accept headers). Somehow Android is expecting the Python server to send something other than HTTP/1.1 200 OK\nContent-type: text/html
and therefore keeping the socket open. I ended up writing my own basic HTTP server and client.
Python code:
class SingleTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request.recv(1024)
parts = data.rsplit(" ")
if (parts[0] != "GET"):
self.request.close()
return
url = parts[1].split("?")[1]
qv = parse_qs(url)
...
Android:
Socket socket = null;
PrintWriter output = null;
try {
socket = new Socket(this.ipAddress, this.portNo);
output = new PrintWriter(new BufferedWriter
(new OutputStreamWriter(socket.getOutputStream())), true);
output.println("GET " + url);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
if (output != null)
output.close();
}
Upvotes: 1