Не удается прочитать сокет InputStream на Jelly Bean

У меня есть соединение сокетов TCP, которое хорошо работает на Android 2.3, но теперь сталкивается с некоторыми проблемами на Android 4.1. Проблема в том, что метод InputStream.read () всегда возвращает -1 (без блокировки), например, соединение закрыто.

Создание сокета:

SocketFactory socketFactory = SocketFactory.getDefault(); Socket socket = socketFactory.createSocket("c.whatsapp.net", 5222); socket.setSoTimeout(3*60*1000); socket.setTcpNoDelay(true); 

Получение входных и выходных потоков и запись некоторых исходных данных:

 InputStream inputStream = new BufferedInputStream(socket.getInputStream()); OutputStream outputStream = new BufferedOutputStream(socket.getOutputStream()); outputStream.write(87); outputStream.write(65); outputStream.write(1); outputStream.write(2); outputStream.flush(); 

Затем это условие всегда проходит без блокировки:

 int c = inputStream.read(); if (c < 0) { Log.d(TAG, "End of stream"); } 

Этот код работает в фоновом потоке . И он работал над пряниками.

Пытался использовать InputStreamReader и OutputStreamWriter вместо прямых потоков – никакого эффекта.

Solutions Collecting From Web of "Не удается прочитать сокет InputStream на Jelly Bean"

Я видел ту же самую ошибку раньше, хотя этот ответ может выглядеть оффтопным, дайте ему шанс и сообщите мне, если это сработало, по какой-то причине сокеты имеют странное поведение на желе, даже когда они отлично работают в нижних версиях Android, Кстати, я решил, что эта проблема состояла в том, чтобы переместить targetSdkVersion в jelly bean, а также в Project Build Target в свойствах Android проекта, не изменил ни одной строки кода, просто так, и по какой-то причине он делает трюк. ,

Надеюсь это поможет.

С уважением!

У меня была аналогичная проблема, когда inputStream.read() возвращал -1, и я не получал исключений. На самом деле сервер был отключен, и соединение сломалось. Я не тестировал его с разными версиями, только с 4.0.

Вот отчет об ошибке Google об этом поведении.

К сожалению, статус ошибки, похоже, «закрыт» как невоспроизводимый.

Моя работа заключалась в том, чтобы интерпретировать -1 как закрытие сокета и недостижимого сервера. Когда вы пытаетесь восстановить соединение, вы получаете правильные ошибки.

У меня была аналогичная проблема, и я исправил ее с таким обходным решением

 private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); private static class WatchDog implements Runnable{ private Thread thread = Thread.currentThread(); public void run() { Log.d(LOG_TAG, "Interrupting read due to timeout"); thread.interrupt(); } } private void read(InputStream in, ByteBuffer bb, long waitTime) throws IOException { int startingPos = bb.position(); long timeout = System.currentTimeMillis() + RESPONSE_TIMEOUT; ScheduledFuture<?> watchdogFuture = executor.schedule(new WatchDog(), RESPONSE_TIMEOUT, TimeUnit.MILLISECONDS); try { while(System.currentTimeMillis() < timeout && bb.hasRemaining()){ //workaround fixing timeout after 1ms try{ int read = in.read(bb.array(), bb.position(), bb.remaining()); if(read > 0){ bb.position(bb.position()+read); } } catch(SocketTimeoutException e){} if(bb.hasRemaining()){ Thread.sleep(5); } } watchdogFuture.cancel(true); } catch (InterruptedException e) {} if(bb.hasRemaining()){ throw new SocketTimeoutException("Unable to read requested bytes: " + (bb.position()-startingPos) + "/" + (bb.limit()-startingPos) + " after " + (System.currentTimeMillis() - timeout + RESPONSE_TIMEOUT) + "ms"); } } 

Использование BufferedReader и PrintWriter работает со всеми версиями для меня и чрезвычайно удобен для отправки и получения всего, что угодно (даже строки JSON) через любой протокол связи. Попробуйте сохранить их в качестве переменных-членов при запуске фонового потока следующим образом:

 mInput = new BufferedReader(new InputStreamReader( socket.getInputStream())); mOutput = new PrintWriter(new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())), true); 

Для асинхронной связи ваш фоновый поток может выглядеть следующим образом:

 @Override public final void run() { while (!Thread.currentThread().isInterrupted()) { if (mInput == null) { break; } String message = null; try { message = mInput.readLine(); } catch (IOException e) { // handle the exception as you like break; } if (Thread.currentThread().isInterrupted()) { // thread was interrupted while reading break; } else if (message != null) { // handle the message as you like } } } 

Для отправки сообщений используйте другой фоновый поток:

 @Override public void run() { if (mOutput != null) { mOutput.println(<message to be ); if (mOutput == null) { // the above thread was interrupted while writing } else if (!mOutput.checkError()) { // everything went fine } else { // handle the exception } } } 

Кроме того, вам придется закрыть потоки извне, чтобы readLine не блокировался навсегда:

 try { mOutput.close(); mInput.close(); mOutput = null; mInput = null; } catch (IOException e) { // log the exception } 

Теперь, поскольку вы используете сокеты TCP, может случиться так, что сокет действительно мертв, а readLine все еще блокирует. Вы должны обнаружить это и закрыть потоки, как указано выше. Для этого вам придется добавить еще один поток (ну хорошо), который периодически отправляет сообщения keep-alive. Если на удаленном устройстве не было получено ни одного сообщения за X секунд, он должен закрыть потоки.

Весь этот подход гарантирует, что розетка закрыта, и все потоки будут закрыты при любых обстоятельствах. Конечно, вы можете сделать синхронное сообщение, если это вам нужно, удалив поток-отправитель и включив println () внутри читательского потока. Надеюсь, это поможет вам (хотя ответ приходит на 8 месяцев позже).

Друг,

Попробуйте inputStream.readLine(); (Т.е.) DataInputStream.readLine(); (Устаревший метод)

Это сработало для меня …

Попробуйте этот код –

 Runnable runnable = new Runnable() { @Override public void run() { synchronized (this) { Socket s = null; String inMsg = null, msg2 = null; try { try { s = new Socket(server, port); } catch (Exception e) { return; } BufferedReader in = new BufferedReader( new InputStreamReader(s.getInputStream())); BufferedWriter out = new BufferedWriter( new OutputStreamWriter(s.getOutputStream())); try { inMsg = in.readLine() + System.getProperty("line.separator"); } catch (Exception e) { return; } out.write(message + "\n\r"); out.flush(); try { msg2 = in.readLine(); if (msg2 == null) { return; } } catch (Exception e) { return; } out.close(); s.close(); } catch (Exception e) { return; } } } }; 

Меня устраивает.