Android – Socket conectado aunque no pueda

En primer lugar sé lo que su pensamiento, es una pregunta extraña y parece que no puede ser cierto, pero aquí me en este …

El proyecto es un proyecto que envía una matriz de bytes sobre un socket y también recibe datos de un socket. Actualmente estoy trabajando en la protección. Quiero asegurarme de que el usuario sepa cuando el socket no se puede conectar por la razón que sea … Puede ver el código de conexión a continuación.

Así que tengo una aplicación para Android que se conecta a un ejecutable en un equipo Windows Server en una oficina en otras partes del mundo. El socket se conecta a través de la dirección IP y el número de puerto habituales.

Estoy probando la aplicación usando un teléfono Android 5.0 (piruleta) …

Ahora bastante de la materia aburrida: Si cierro el servidor y lo apago completamente y pruebo esto en wi-fi entonces el socket falla – que es correcto. No se puede conectar y lanzará una excepción SocketException. Que está bien y está funcionando como se esperaba. Ahora, si yo fuera a desactivar el wi-fi y el uso de datos móviles (yo uso o2 aquí en el soleado Reino Unido!) Entonces surge un problema, utilizando el mismo código, con el servidor todavía apagado, no lanzar una SocketException, En su lugar, el código simple cree que se ha conectado en un zócalo. El hilo de conexión está debajo.

Thread StartConnection = new Thread() { @Override public void run() { int dstPort = 10600; socket = new Socket(); try { ipaddress = InetAddress.getByName(dstName); } catch (UnknownHostException uhe) { uhe.printStackTrace(); } j = new InetSocketAddress(IPString , dstPort); try { socket.setKeepAlive(true); socket.setReuseAddress(true); socket.setTcpNoDelay(true); socket.setSoTimeout(5000); socket.connect(j, 5000); connected = true; outputstream = socket.getOutputStream(); DataThread(); SocketError = false; } catch (SocketException se) { se.printStackTrace(); } catch (IllegalArgumentException iae) { iae.printStackTrace(); } catch (IOException ioe) { ioe.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } }; StartConnection.start(); 
 socket.connect(j, 5000); 

Funciona bien sin errores de socket. Sin tiempos de espera tampoco.

 outputstream = socket.getOutputStream(); 

También funciona. Obtengo un resultado de "java.net.PlainSocketImpl$PlainSocketOutputStream@48e6f6e" que también está bien.

socket.getInputStream() devuelve "java.net.PlainSocketImpl$PlainSocketInputStream@1ea305a5"

Esto es interesante. He estado probando y puedo replicar el comportamiento que usted describe.

En primer lugar, la respuesta más votada aquí proporciona una buena discusión sobre el Java Socket API:

Java socket API: ¿Cómo saber si una conexión ha sido cerrada?

A partir de esto, me preguntaba si intentar leer un byte desde el socket nos permitiría comprobar si está realmente abierto

 // Endpoint that does not exist Socket socket = new Socket("1.2.3.4", 1234); InputStream tmpIn = socket.getInputStream(); int result = tmpIn.read(); Log.i("SocketTest", "read() result: " + result); 

En el caso de que el punto final no es válido, he encontrado que la llamada a read() devuelve -1 después de aproximadamente 10 segundos.

En el caso de que hay un oyente en la IP y el puerto, la llamada a read() parece bloquear indefinidamente hasta que algo sucede, como realmente la recepción de datos desde el servidor, o perder la conexión a Internet, etc

Sobre la base de esta diferencia, he envuelto esta prueba en una nueva clase:

 public class VerifiedSocket extends Socket { public VerifiedSocket(String ip, int port, int millisecondTimeout) throws UnknownHostException, IOException{ super(ip,port); ReadThread tryRead = new ReadThread(); tryRead.start(); try { tryRead.join(millisecondTimeout); } catch (InterruptedException e) { } if(tryRead.getReadValue()==-1){ // We read -1 so assume endpoint invalid throw new IOException("Endpoint is invalid"); } } private class ReadThread extends Thread{ private int readValue = 512; // Impossible byte value @Override public void run(){ try { InputStream input = getInputStream(); readValue = input.read(); } catch (IOException e) { } } public int getReadValue(){ return readValue; } } } 

Y luego probarlo de la siguiente manera:

 try { VerifiedSocket socket = new VerifiedSocket("1.2.3.4", 1234, 20000); Log.i("SocketTest", "Endpoint is valid"); socket.close(); } catch (UnknownHostException e) { Log.e("SocketTest", e.getLocalizedMessage()); } catch (IOException e) { Log.e("SocketTest", e.getLocalizedMessage()); } 

Si utilizo un punto final no válido en Wifi, el constructor de VerifiedSocket lanza una excepción con un tiempo de espera. Si utilizo un punto final no válido en datos móviles, lanza IOException con el mensaje 'Endpoint is invalid'. No es perfecto, pero espero que pueda ayudarte.

Si el entorno donde está ejecutando el código no se comporta como usted necesita (por cualquier razón, Robert ha escrito uno), puede resolver el mal comportamiento entorno con traer una nueva abstracción.

Usted puede hacer muchas cosas para resolverlo; Aquí hay una solución – implementar un envoltorio en la parte superior del protocolo utilizado (java.net.Socket) que extenderá la clase Socket y reemplazará los métodos connect () / getInputStream () / getOutputStream () / whatever-method-you-need () La forma en que el código primero intenta contactar realmente al servidor antes de devolver un flujo válido.

En el envoltorio, envía un par de bytes (una clave de cliente) al servidor en el que el servidor responde con una respuesta (una clave de servidor). Mantenga las claves en secreto, solo el cliente y el servidor conocerán las claves. Si el servidor no responde con un tiempo de espera, lance una excepción.

 private class MySocket extends Socket { Socket inner; MySocket(Socket inner) { this.inner = inner; } @Override InputStream getInputStream() { // do your ping here // if ping fails, thrown an exception return inner.getInputStream(); } ... override additional methods as you need } 

Puede utilizar este patrón de ping en todos los lugares para detectar la conexión se perdió.

Sé que estás haciendo lo que la capa subyacente se supone que está haciendo … pero si no está haciendo lo que estás esperando, ¿qué puedes hacer?

  • Socket android DataOutputStream.writeUTF
  • ¿Cuál es la diferencia entre DataOutputStream y ObjectOutputStream?
  • Android: socket bluetooth se niegan a conectarse correctamente
  • Retraso / retraso enorme de UDP con Android
  • Los sockets "localhost" de Android fallan cuando no hay conexión de datos?
  • Dispositivos Android conectados con NSD, cómo enviar mensajes utilizando sockets (Client-Client)?
  • Conectarse al conector Bluetooth de Android
  • ¿Cómo leer la respuesta HTTP a través de sockets?
  • Android BluetoothSocket OutputStream escribe bloques de forma infinita
  • Sockets sin procesar en Android
  • Enviar texto a través de Bluetooth desde Java Server a Android Client
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.