2009-06-09 49 views
22

Cuando estoy usando p. Ej. PuTTY y mi conexión se pierde (o cuando hago un manual ipconfig /release en Windows), responde directamente y notifica que mi conexión se perdió.Java detectar conexión perdida

Quiero crear un programa Java que supervise mi conexión a Internet (a algún servidor confiable), para registrar la fecha/horas en que mi internet falla.

He intentado utilizar el método Socket.isConnected(), pero eso siempre devolverá "verdadero". ¿Cómo puedo hacer esto en Java?

Respuesta

18

Bueno, la mejor manera de saber si su conexión se interrumpe es tratar de leer/escribir desde el socket. Si la operación falla, entonces habrá perdido su conexión en algún momento.

Por lo tanto, todo lo que necesita hacer es intentar leer en algún intervalo, y si la lectura falla, intente reconectar.

Los eventos importantes para usted serán cuando una lectura falla, perdió la conexión y cuando se conecta una toma nueva, recuperó la conexión.

De esta forma puede realizar un seguimiento del tiempo de actividad y del tiempo de inactividad.

+0

No es correcto. Si ha establecido un tiempo de espera de lectura y activa una excepción, es decir, la operación falla, pero no necesariamente indica una conexión perdida. – EJP

+2

@EJP No siempre es correcto, pero le dará una buena idea sobre lo que está sucediendo. – jjnguy

+11

No, no lo hará. No puede distinguir entre un servidor lento y una conexión perdida con un tiempo de espera de lectura. – EJP

7

¿Por qué no utilizar el método isReachable() de la clase java.net.InetAddress?

¿Cómo funciona esto es la implementación JVM específica, sino:

Una aplicación típica utilizará peticiones de eco ICMP si se puede obtener el privilegio, de lo contrario se tratará de establecer una conexión TCP en el puerto 7 (Echo) de el host de destino

Si desea mantener una conexión abierta continuamente para que pueda ver cuando eso falla que podría conectar con el servidor que ejecuta el ECHO protocol a sí mismo en lugar de tener isReachable() que lo haga por usted y leer y escribir datos y esperar a que falle .

+1

Hmm tal vez no estaba claro en mi pregunta. Lo que a veces sucede en my systen es que mi conexión a Internet se cae durante unos segundos y todas las conexiones se cierran. Un segundo después todo está bien. Quiero monitorear esto diariamente, para hacer informes con qué frecuencia esto está sucediendo. – kresjer

+0

Puede conectarse usted mismo a un servidor ECHO y seguir enviando y leyendo datos; agregó esto a la respuesta. –

+0

Si una conexión existente todavía está abierta no tiene nada que ver con 'isReachable()' en absoluto. – EJP

0

Puede hacer ping a una máquina cada varios segundos, y esto sería bastante preciso. Tenga cuidado de que no lo haga en DOS.

Otra alternativa sería ejecutar un pequeño servidor en una máquina remota y mantener una conexión con ella.

+0

¿Cómo sabría cuándo se desconectó del pequeño servidor? Y un ** gran ** uso de Java es en los dispositivos móviles Android donde los constantes ping y keepalives son una mala idea porque matan la batería. – user316117

0

Es probablemente más fácil de conectar a yahoo/google o en algún lugar como este.

URL yahoo = new URL("http://www.yahoo.com/"); 
    URLConnection yc = yahoo.openConnection(); 
    int dataLen = yc.getContentLength() ; 

Neil

+0

Nada que ver con si una conexión existente todavía está abierta. – EJP

+0

La pregunta fue cómo escribir un "programa Java que supervisa mi conexión a Internet", que esto funcionará bien. Java directamente no puede monitorear si se pierde la conexión de masilla, pero dirá cuándo ocurre un problema de red genérico. Puede llamar a "netstat" desde java para monitorear una conexión de red desde otro proceso. –

+0

Los programadores de Windows que usan WinSock pueden registrarse para un evento. Esto se dispara incluso después de desconectar un cable. (con unos segundos de retraso) [https://stackoverflow.com/questions/44681648/in-android-how-can-i-receive-an-event-when-my-socket-closes-or-disconnects](link) – user316117

1

Es posible que desee intente buscar en la toma timeout interval. Con un tiempo de espera corto (I cree que el valor predeterminado es 'tiempo de espera infinito'), entonces es posible que pueda atrapar una excepción o algo cuando el host no se puede alcanzar.

+1

Esto no detecta todos los casos. Tienes que leer o escribir algo en el socket. – tputkonen

10

Aunque TCP/IP es un protocolo "orientado a la conexión", normalmente no se envían datos a través de una conexión inactiva. Puede tener un socket abierto durante un año sin un solo bit enviado por la pila IP. Para notar que se pierde una conexión, debe enviar algunos datos en el nivel de la aplicación. (*) Puede probar esto desconectando el cable del teléfono de su módem ADSL. Todas las conexiones en su PC deben permanecer activas, a menos que las aplicaciones tengan algún tipo de mecanismo keepalive de nivel de aplicación.

De modo que la única forma de notar la pérdida de conexión es abrir la conexión TCP a algún servidor y leer algunos datos de la misma. Quizás la forma más simple podría ser conectarse a un servidor FTP y buscar un archivo pequeño, o una lista de directorios, de vez en cuando. Nunca he visto un servidor genérico que realmente haya sido diseñado para este caso, y puede que los propietarios del servidor FTP no quieran que los clientes lo hagan.

(*) También hay un mecanismo llamado de mantenimiento de conexión TCP, pero en muchos sistemas operativos que hay que activarlo para todas las aplicaciones, y no es muy práctico de usar si quieres notar pérdida de conexión rápida

1

Vale así que finalmente conseguí que trabajaba con

try 
{ 
    Socket s = new Socket("stackoverflow.com",80); 
    DataOutputStream os = new DataOutputStream(s.getOutputStream()); 
    DataInputStream is = new DataInputStream(s.getInputStream()); 
    while (true) 
    { 
     os.writeBytes("GET /index.html HTTP/1.0\n\n"); 
     is.available(); 
     Thread.sleep(1000); 
    } 
} 
catch (IOException e) 
{ 
    System.out.println("connection probably lost"); 
    e.printStackTrace(); 
} 

no tan limpio como lo esperaba, pero no está funcionando si dejo a cabo las os.writeBytes().

+17

Esto es algo que definitivamente no deberías usar. ¡Casi se puede considerar como un ataque DOS contra stackoverflow.com! – tputkonen

+0

Una forma más amigable de hacer esto sería alojar una página/script simple en un host web que (probablemente) no le importaría una carga constante como esta, especialmente si la página renderizada era pequeña (solo una simple "h" haría) Esto debería proporcionar una pequeña huella y si las llamadas se hacen cada segundo o más, el servidor probablemente no se atasque dando como resultado un DOS. En teoría de todos modos. – Kingsolmn

+4

Esto no tiene sentido. Llamar disponible() generalmente no tiene sentido, y llamarlo y tirar el resultado definitivamente así. El sueño es literalmente una pérdida de tiempo. Esta técnica no logra precisamente nada. – EJP

4

Si el cliente tiene desconecta correctamente, un read() volverá -1, readLine() vuelve nula, readXXX() para cualquier otro X tiros EOFException. La única forma confiable de detectar una conexión TCP perdida es escribir en ella. Eventualmente arrojará un 'reset de conexión' IOException, pero se requieren al menos dos escrituras debido al almacenamiento en búfer.

1

El método isConnected() dentro de la clase Socket.java es un poco engañoso. No le dice si el socket está actualmente conectado a un host remoto (como si no estuviera cerrado). En cambio, le dice si el socket alguna vez se ha conectado a un host remoto. Si el socket fue capaz de conectarse al host remoto, este método devuelve true, incluso después de que se cerró ese socket. Para saber si un socket está actualmente abierto, debe verificar que isConnected() devuelva true y isClosed() devuelve false. Por ejemplo:

boolean connected = socket.isConnected() && !socket.isClosed(); 
+0

_Para saber si un socket está actualmente abierto, debe verificar que isConnected() devuelve true y isClosed() devuelve false_ Esto no parece ser cierto. Ver: [https://stackoverflow.com/questions/44685374/why-am-i-sending-an-rst-if-my-socket-is-connected-and-not-closed] (enlace) – user316117

+0

@ user316117 que La pregunta no está clara, pero si el isClosed es FALSE y el isConnected es TRUE significa que usted logró conectarse y nunca se cerró la conexión. Si crees que estás desconectado y el "isClosed()" devuelve FALSE, entonces has descubierto un error JDK. Consulte esta documentación: https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#isConnected-- – Alboz

+0

@Alboz Significa que logró conectarse y * socket * no tiene cerrado aún No tiene nada que ver con la conexión, como tú mismo lo dijiste en tu propia respuesta. No hay ningún error JDK a menos que haya cerrado su propio socket y luego haya 'isClosed() == false'. – EJP

Cuestiones relacionadas