Этот сводит меня с ума в течение нескольких дней. Это очень сложно объяснить и понять, но я сделаю все возможное. Пожалуйста, задавайте любые вопросы, если мне неясно где-либо. Эта проблема возникает только тогда, когда я отправляю большой пакет, размером более 300 КБ, например изображение. Отправка небольших пакетов работает нормально.
У меня есть служба Android, которая обменивается данными с JSON-RPC-сервером на основе Python. При общении через WiFi или 3G все работает нормально. Однако при общении через EDGE все идет ужасно неправильно. Приложение Android создает HttpClient и HttpPost. Запрос сделан, однако ответ никогда не получен от сервера. Я поместил несколько операторов журнала до и после запроса 'execute', и он никогда не проходит мимо этого. Также кажется, что запрос сделан СНОВА, если первоначальная попытка была неудачной. У меня есть лог-операторы в каждом из блоков «catch», и ни один из них не выполняется, поэтому кажется, что HTTP-запрос снова как-то повторяется внутри.
Я изучал код RPC на своем сервере, и вот что я могу сказать оттуда. Соединение с сокетом установлено, и данные считаны из сокета. Изучение netstat показывает установленное соединение в течение нескольких секунд, затем оно переходит в CLOSE_WAIT. Как только это происходит, данные больше не считываются из сокета (очевидно), и сервер находится в непрерывном цикле, пока соединение с сокетом не будет разорвано. На этом этапе я убивал службу JSON-RPC и отключал ее. Если я не убью его, служба будет занимать 100% процессорного времени, и я оставлю его на 5 минут, и, похоже, он не отключит сокет.
Вот код для выполнения вызова RPC с устройства Android:
DefaultHttpClient client = new DefaultHttpClient();
try {
HttpPost post = new HttpPost(url);
post.setHeader("Content-Type", "application/json");
post.setEntity(new ByteArrayEntity(data));
// I tried these lines on the HttpPost but didn't seem
// to make a difference.
HttpProtocolParams.setVersion(client.getParams(), HttpVersion.HTTP_1_1);
HttpProtocolParams.setUseExpectContinue(client.getParams(), false);
// This doesn't seem to do anything at all...
client.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
Log.d("MyAppName", "** About to make HTTP request");
String json = client.execute(post, new BasicResponseHandler());
Log.d("MyAppName", "** Returned from HTTP request!");
JSONObject obj = new JSONObject(json);
if (obj.isNull("result")) {
rtnval = obj.getJSONObject("error").getString("message");
} else {
// More code here...
}
} catch (ClientProtocolException cpe) {
Log.e("MyAppName", "EXCEPTION: " + cpe.getMessage());
} catch (IOException ioe) {
Log.e("MyAppName", "EXCEPTION: " + ioe.getMessage());
} catch (JSONException je) {
Log.e("MyAppName", "EXCEPTION: " + je.getMessage());
} finally {
client.getConnectionManager().shutdown();
}
Код "нарушителя" на стороне RPC фактически находится в (Python2.7) SimpleXMLRPCServer.py в цикле while в строке # 487. Строка «self.rfile.read» - это то, что непрерывно получает 0 байтов, которые никогда не уменьшают size_remaining и, следовательно, никогда не покидают цикл. Я не слишком обеспокоен этим, я действительно хотел бы знать, почему связь прерывается, но я добавил это в вопросе ради полноты.
Итак, я пытаюсь выяснить, как HTTP-соединение входит в CLOSE_WAIT. Похоже, что он исходит от устройства Android, но я не могу понять это наверняка. Я попытался установить для параметра ByteArrayEntity фрагментацию, но, как представляется, в нем отсутствует заголовок «Content-Length», который требуется для JSON-RPC.
Если кто-то знает, что я могу сделать, чтобы сохранить это соединение дольше или предотвратить его закрытие, я был бы очень признателен. Я также хотел бы предотвратить повторную попытку HTTP-запроса. Спасибо за любую помощь!