Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


IOException: error de lectura, socket podría cerrarse – Bluetooth en Android 4.3

Actualmente estoy tratando de hacer frente a una extraña Excepción al abrir un BluetoothSocket en mi Nexus 7 (2012), con Android 4.3 (Build JWR66Y, supongo que la segunda actualización 4.3). He visto algunas publicaciones relacionadas (por ejemplo, https://stackoverflow.com/questions/13648373/bluetoothsocket-connect-throwing-exception-read-failed ), pero ninguna parece proporcionar una solución para este problema. Además, como se sugiere en estos hilos, re-emparejamiento no ayuda, y constantemente tratando de conectar (a través de un bucle estúpido) también no tiene ningún efecto.

Estoy tratando con un dispositivo incorporado (un adaptador del coche del noname OBD-II, similar a http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE- LUCES-CON-SU-TELÉFONO-Oceanside.jpg ). Mi teléfono Android 2.3.7 no tiene problemas de conexión, y el Xperia de un colega (Android 4.1.2) también funciona. Otro Nexo de Google (no sé si 'Uno' o 'S', pero no '4') también falla con Android 4.3.

Aquí está el fragmento del establecimiento de la conexión. Se está ejecutando en su propio hilo, creado dentro de un servicio.

private class ConnectThread extends Thread { private static final UUID EMBEDDED_BOARD_SPP = UUID .fromString("00001101-0000-1000-8000-00805F9B34FB"); private BluetoothAdapter adapter; private boolean secure; private BluetoothDevice device; private List<UUID> uuidCandidates; private int candidate; protected boolean started; public ConnectThread(BluetoothDevice device, boolean secure) { logger.info("initiliasing connection to device "+device.getName() +" / "+ device.getAddress()); adapter = BluetoothAdapter.getDefaultAdapter(); this.secure = secure; this.device = device; setName("BluetoothConnectThread"); if (!startQueryingForUUIDs()) { this.uuidCandidates = Collections.singletonList(EMBEDDED_BOARD_SPP); this.start(); } else{ logger.info("Using UUID discovery mechanism."); } /* * it will start upon the broadcast receive otherwise */ } private boolean startQueryingForUUIDs() { Class<?> cl = BluetoothDevice.class; Class<?>[] par = {}; Method fetchUuidsWithSdpMethod; try { fetchUuidsWithSdpMethod = cl.getMethod("fetchUuidsWithSdp", par); } catch (NoSuchMethodException e) { logger.warn(e.getMessage()); return false; } Object[] args = {}; try { BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { BluetoothDevice deviceExtra = intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE"); Parcelable[] uuidExtra = intent.getParcelableArrayExtra("android.bluetooth.device.extra.UUID"); uuidCandidates = new ArrayList<UUID>(); for (Parcelable uuid : uuidExtra) { uuidCandidates.add(UUID.fromString(uuid.toString())); } synchronized (ConnectThread.this) { if (!ConnectThread.this.started) { ConnectThread.this.start(); ConnectThread.this.started = true; unregisterReceiver(this); } } } }; registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID")); registerReceiver(receiver, new IntentFilter("android.bluetooth.device.action.UUID")); fetchUuidsWithSdpMethod.invoke(device, args); } catch (IllegalArgumentException e) { logger.warn(e.getMessage()); return false; } catch (IllegalAccessException e) { logger.warn(e.getMessage()); return false; } catch (InvocationTargetException e) { logger.warn(e.getMessage()); return false; } return true; } public void run() { boolean success = false; while (selectSocket()) { if (bluetoothSocket == null) { logger.warn("Socket is null! Cancelling!"); deviceDisconnected(); openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION); } // Always cancel discovery because it will slow down a connection adapter.cancelDiscovery(); // Make a connection to the BluetoothSocket try { // This is a blocking call and will only return on a // successful connection or an exception bluetoothSocket.connect(); success = true; break; } catch (IOException e) { // Close the socket try { shutdownSocket(); } catch (IOException e2) { logger.warn(e2.getMessage(), e2); } } } if (success) { deviceConnected(); } else { deviceDisconnected(); openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION); } } private boolean selectSocket() { if (candidate >= uuidCandidates.size()) { return false; } BluetoothSocket tmp; UUID uuid = uuidCandidates.get(candidate++); logger.info("Attempting to connect to SDP "+ uuid); try { if (secure) { tmp = device.createRfcommSocketToServiceRecord( uuid); } else { tmp = device.createInsecureRfcommSocketToServiceRecord( uuid); } bluetoothSocket = tmp; return true; } catch (IOException e) { logger.warn(e.getMessage() ,e); } return false; } } 

El código está fallando en bluetoothSocket.connect() . Estoy recibiendo una java.io.IOException: read failed, socket might closed, read ret: -1 . Esta es la fuente correspondiente en GitHub: https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L504 Su llamado a través readInt (), llamado desde https : //github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothSocket.java#L319

Algunos volcados de metadatos del socket utilizado resultaron en la siguiente información. Estos son exactamente los mismos en Nexus 7 y mi teléfono 2.3.7.

 Bluetooth Device 'OBDII' Address: 11:22:33:DD:EE:FF Bond state: 12 (bonded) Type: 1 Class major version: 7936 Class minor version: 7936 Class Contents: 0 Contents: 0 

Tengo algunos otros adaptadores de OBD-II (más expansives) y todos trabajan. ¿Hay alguna posibilidad, que me falta algo o que esto podría ser un error en Android?

9 Solutions collect form web for “IOException: error de lectura, socket podría cerrarse – Bluetooth en Android 4.3”

Finalmente he encontrado una solución. La magia se oculta bajo el capó de la clase BluetoothDevice (consulte https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037 ).

Ahora, cuando recibo esa excepción, instanciar un fallback BluetoothSocket , similar al código fuente de abajo. Como puede ver, invocando el método oculto createRfcommSocket vía reflexiones. No tengo ni idea de por qué este método está oculto. El código fuente lo define como public aunque …

 Class<?> clazz = tmp.getRemoteDevice().getClass(); Class<?>[] paramTypes = new Class<?>[] {Integer.TYPE}; Method m = clazz.getMethod("createRfcommSocket", paramTypes); Object[] params = new Object[] {Integer.valueOf(1)}; fallbackSocket = (BluetoothSocket) m.invoke(tmp.getRemoteDevice(), params); fallbackSocket.connect(); 

connect() entonces no falla más. He experimentado algunos problemas todavía. Básicamente, esto a veces bloquea y falla. La reinicialización del dispositivo SPP (enchufe / enchufe) ayuda en estos casos. A veces también obtengo otra solicitud de emparejamiento después de connect() incluso cuando el dispositivo ya está enlazado.

ACTUALIZAR:

Aquí hay una clase completa, que contiene algunas clases anidadas. Para una implementación real, éstas podrían llevarse a cabo como clases separadas.

 import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Method; import java.util.List; import java.util.UUID; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.util.Log; public class BluetoothConnector { private BluetoothSocketWrapper bluetoothSocket; private BluetoothDevice device; private boolean secure; private BluetoothAdapter adapter; private List<UUID> uuidCandidates; private int candidate; /** * @param device the device * @param secure if connection should be done via a secure socket * @param adapter the Android BT adapter * @param uuidCandidates a list of UUIDs. if null or empty, the Serial PP id is used */ public BluetoothConnector(BluetoothDevice device, boolean secure, BluetoothAdapter adapter, List<UUID> uuidCandidates) { this.device = device; this.secure = secure; this.adapter = adapter; this.uuidCandidates = uuidCandidates; if (this.uuidCandidates == null || this.uuidCandidates.isEmpty()) { this.uuidCandidates = new ArrayList<UUID>(); this.uuidCandidates.add(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); } } public BluetoothSocketWrapper connect() throws IOException { boolean success = false; while (selectSocket()) { adapter.cancelDiscovery(); try { bluetoothSocket.connect(); success = true; break; } catch (IOException e) { //try the fallback try { bluetoothSocket = new FallbackBluetoothSocket(bluetoothSocket.getUnderlyingSocket()); Thread.sleep(500); bluetoothSocket.connect(); success = true; break; } catch (FallbackException e1) { Log.w("BT", "Could not initialize FallbackBluetoothSocket classes.", e); } catch (InterruptedException e1) { Log.w("BT", e1.getMessage(), e1); } catch (IOException e1) { Log.w("BT", "Fallback failed. Cancelling.", e1); } } } if (!success) { throw new IOException("Could not connect to device: "+ device.getAddress()); } return bluetoothSocket; } private boolean selectSocket() throws IOException { if (candidate >= uuidCandidates.size()) { return false; } BluetoothSocket tmp; UUID uuid = uuidCandidates.get(candidate++); Log.i("BT", "Attempting to connect to Protocol: "+ uuid); if (secure) { tmp = device.createRfcommSocketToServiceRecord(uuid); } else { tmp = device.createInsecureRfcommSocketToServiceRecord(uuid); } bluetoothSocket = new NativeBluetoothSocket(tmp); return true; } public static interface BluetoothSocketWrapper { InputStream getInputStream() throws IOException; OutputStream getOutputStream() throws IOException; String getRemoteDeviceName(); void connect() throws IOException; String getRemoteDeviceAddress(); void close() throws IOException; BluetoothSocket getUnderlyingSocket(); } public static class NativeBluetoothSocket implements BluetoothSocketWrapper { private BluetoothSocket socket; public NativeBluetoothSocket(BluetoothSocket tmp) { this.socket = tmp; } @Override public InputStream getInputStream() throws IOException { return socket.getInputStream(); } @Override public OutputStream getOutputStream() throws IOException { return socket.getOutputStream(); } @Override public String getRemoteDeviceName() { return socket.getRemoteDevice().getName(); } @Override public void connect() throws IOException { socket.connect(); } @Override public String getRemoteDeviceAddress() { return socket.getRemoteDevice().getAddress(); } @Override public void close() throws IOException { socket.close(); } @Override public BluetoothSocket getUnderlyingSocket() { return socket; } } public class FallbackBluetoothSocket extends NativeBluetoothSocket { private BluetoothSocket fallbackSocket; public FallbackBluetoothSocket(BluetoothSocket tmp) throws FallbackException { super(tmp); try { Class<?> clazz = tmp.getRemoteDevice().getClass(); Class<?>[] paramTypes = new Class<?>[] {Integer.TYPE}; Method m = clazz.getMethod("createRfcommSocket", paramTypes); Object[] params = new Object[] {Integer.valueOf(1)}; fallbackSocket = (BluetoothSocket) m.invoke(tmp.getRemoteDevice(), params); } catch (Exception e) { throw new FallbackException(e); } } @Override public InputStream getInputStream() throws IOException { return fallbackSocket.getInputStream(); } @Override public OutputStream getOutputStream() throws IOException { return fallbackSocket.getOutputStream(); } @Override public void connect() throws IOException { fallbackSocket.connect(); } @Override public void close() throws IOException { fallbackSocket.close(); } } public static class FallbackException extends Exception { /** * */ private static final long serialVersionUID = 1L; public FallbackException(Exception e) { super(e); } } } 

Bueno, tuve el mismo problema con mi código, y es porque desde android 4.2 bluetooth pila ha cambiado. Por lo que mi código estaba funcionando bien en los dispositivos con android <4.2, en los otros dispositivos que estaba recibiendo la famosa excepción "leer falló, socket puede cerrado o tiempo de espera, read ret: -1"

El problema es con el parámetro socket.mPort . Cuando crea su socket utilizando socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID); , El mPort obtiene el valor entero " -1 ", y este valor parece que no funciona para android> = 4.2, por lo que necesita establecerlo en " 1 ". La mala noticia es que createRfcommSocketToServiceRecord sólo acepta UUID como parámetro y no mPort por lo que tenemos que usar otro approach. La respuesta publicada por @matthes también funcionó para mí, pero lo simplifiqué: socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1); . Tenemos que usar los dos atributos de socket, el segundo como un fallback.

Así que el código es (para conectarse a un SPP en un dispositivo ELM327):

 BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter(); if (btAdapter.isEnabled()) { SharedPreferences prefs_btdev = getSharedPreferences("btdev", 0); String btdevaddr=prefs_btdev.getString("btdevaddr","?"); if (btdevaddr != "?") { BluetoothDevice device = btAdapter.getRemoteDevice(btdevaddr); UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); // bluetooth serial port service //UUID SERIAL_UUID = device.getUuids()[0].getUuid(); //if you don't know the UUID of the bluetooth device service, you can get it like this from android cache BluetoothSocket socket = null; try { socket = device.createRfcommSocketToServiceRecord(SERIAL_UUID); } catch (Exception e) {Log.e("","Error creating socket");} try { socket.connect(); Log.e("","Connected"); } catch (IOException e) { Log.e("",e.getMessage()); try { Log.e("","trying fallback..."); socket =(BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(device,1); socket.connect(); Log.e("","Connected"); } catch (Exception e2) { Log.e("", "Couldn't establish Bluetooth connection!"); } } } else { Log.e("","BT device not selected"); } } 

Usted pone registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID")); Con el bluetooth deletreado "bleutooth".

Tuve los mismos síntomas que se describen aquí. Podría conectar una vez a una impresora del bluetooth pero conexiones subsecuentes falladas con el "zócalo cerrado" no importa lo que lo hice.

Me pareció un poco extraño que las soluciones descritas aquí sería necesario. Después de pasar por mi código descubrí que había olvidado cerrar el InputStream del zócalo y OutputSteram y no terminar el ConnectedThreads correctamente.

El ConnectedThread que utilizo es el mismo que en el ejemplo aquí:

http://developer.android.com/guide/topics/connectivity/bluetooth.html

Tenga en cuenta que ConnectThread y ConnectedThread son dos clases diferentes.

Cualquiera que sea la clase que inicie el ConnectedThread debe llamar a interrupt () y cancel () en el subproceso. Añadí mmInStream.close () y mmOutStream.close () en el método ConnectedTread.cancel ().

Después de cerrar los hilos / corrientes / sockets correctamente podría crear nuevos sockets sin ningún problema.

En primer lugar, si necesita hablar con un dispositivo bluetooth 2.x, esta documentación establece que:

Sugerencia: Si se está conectando a una tarjeta serie Bluetooth, pruebe a utilizar el conocido SPU UUID 00001101-0000-1000-8000-00805F9B34FB . Sin embargo, si se está conectando a un par Android, por favor, genere su propio UUID único.

No pensé que trabajaría, solamente substituyendo el UUID con 00001101-0000-1000-8000-00805F9B34FB él trabaja. Sin embargo, este código parece manejar el problema de la versión de SDK, y sólo puede reemplazar la función device.createRfcommSocketToServiceRecord(mMyUuid); Con tmp = createBluetoothSocket(mmDevice); Después de definir el siguiente método:

 private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException { if(Build.VERSION.SDK_INT >= 10){ try { final Method m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", new Class[] { UUID.class }); return (BluetoothSocket) m.invoke(device, mMyUuid); } catch (Exception e) { Log.e(TAG, "Could not create Insecure RFComm Connection",e); } } return device.createRfcommSocketToServiceRecord(mMyUuid); } 

El código fuente no es mío, pero viene de este sitio web .

Bueno, realmente he encontrado el problema.

La mayoría de las personas que intentan establecer una conexión mediante socket.Connect(); Obtener una excepción llamada Java.IO.IOException: read failed, socket might closed, read ret: -1 .

En algunos casos, también depende de su dispositivo Bluetooth, ya que hay dos tipos diferentes de Bluetooth, es decir, BLE (baja energía) y Classic.

Si desea comprobar el tipo de su dispositivo Bluetooth, aquí está el código:

  String checkType; var listDevices = BluetoothAdapter.BondedDevices; if (listDevices.Count > 0) { foreach (var btDevice in listDevices) { if(btDevice.Name == "MOCUTE-032_B52-CA7E") { checkType = btDevice.Type.ToString(); Console.WriteLine(checkType); } } } 

He estado tratando durante días para resolver el problema, pero desde hoy he encontrado el problema. La solución de @matthes ha desafortunadamente aún algunos problemas como ya dijo, pero aquí está mi solución.

Actualmente trabajo en Xamarin Android, pero esto también debería funcionar para otras plataformas.

SOLUCIÓN

Si hay más de un dispositivo emparejado, debe quitar los otros dispositivos emparejados. Por lo tanto, mantenga sólo el que desea conectar (consulte la imagen de la derecha).

Introduzca aquí la descripción de la imagen Introduzca aquí la descripción de la imagen

En la imagen izquierda ves que tengo dos dispositivos emparejados, a saber "MOCUTE-032_B52-CA7E" y "Blue Easy". Ese es el problema, pero no tengo ni idea de por qué ocurre ese problema. Tal vez el protocolo Bluetooth esté intentando obtener información de otro dispositivo Bluetooth.

Sin embargo, el socket.Connect(); Funciona muy bien en este momento, sin ningún problema. Así que sólo quería compartir esto, porque ese error es realmente molesto.

¡Buena suerte!

En las versiones más recientes de Android, estaba recibiendo este error porque el adaptador todavía estaba descubriendo cuando intenté conectarme al socket. A pesar de que llamé el método cancelDiscovery en el adaptador Bluetooth, tuve que esperar hasta que se llamara la devolución de llamada al método onReceive () de BroadcastReceiver con la acción BluetoothAdapter.ACTION_DISCOVERY_FINISHED.

Una vez que esperé por el adaptador para detener el descubrimiento, entonces la llamada de conexión en el socket tuvo éxito.

I también se enfrentan a este problema, se puede resolver de 2 maneras, como se mencionó anteriormente uso de reflexión para crear el socket Segundo es, el cliente está buscando un servidor con dado UUID y si su servidor no está funcionando paralelo al cliente, entonces este Sucede. Crear un servidor con el cliente dado UUID y luego escuchar y aceptar el cliente desde el lado del servidor. Funcionará.

También he recibido la misma IOException , pero encuentro la demo del sistema Android: "BluetoothChat" proyecto está funcionando. Determiné que el problema es el UUID.

Así que reemplazar mi UUID.fromString("00001001-0000-1000-8000-00805F9B34FB") a UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66") y funcionó la mayoría de la escena, sólo a veces es necesario reiniciar el Bluetooth dispositivo;

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.