2009-06-09 21 views
22

Quando utilizzo, ad es. PuTTY e la mia connessione si perde (o quando faccio un manuale ipconfig /release su Windows), risponde direttamente e notifica che la mia connessione è andata persa.Java ha rilevato la connessione persa

Desidero creare un programma Java che monitora la mia connessione Internet (su un server affidabile), per registrare la data/l'ora in cui Internet non funziona.

Ho provato a utilizzare il metodo Socket.isConnected() ma questo per sempre restituirà "true". Come posso farlo in Java?

risposta

18

Bene, il modo migliore per sapere se la connessione è interrotta è provare a leggere/scrivere dal socket. Se l'operazione fallisce, hai perso la connessione prima o poi.

Quindi, tutto quello che devi fare è provare a leggere ad intervalli, e se la lettura fallisce prova a ricollegarti.

Gli eventi importanti per te saranno quando una lettura fallisce - hai perso la connessione, e quando un nuovo socket è connesso - hai riacquistato la connessione.

In questo modo è possibile tenere traccia del tempo di attività e dei tempi di inattività.

+0

Non corretto. Se hai impostato un timeout di lettura e si attiva, ottieni un'eccezione, cioè l'operazione fallisce, ma non indica necessariamente una connessione persa. – EJP

+2

@EJP Non è sempre corretto, ma ti darà una buona idea di cosa sta succedendo. – jjnguy

+11

No non lo farà. Non è possibile distinguere tra un server lento e una connessione persa con un timeout di lettura. – EJP

7

Perché non utilizzare il metodo isReachable() della classe java.net.InetAddress?

Come funziona è implementazione JVM specifica, ma:

Una tipica applicazione utilizzerà le richieste ICMP ECHO se il privilegio può essere ottenuto, altrimenti si cercherà di stabilire una connessione TCP sulla porta 7 (Echo) della l'host di destinazione.

Se si desidera mantenere una connessione aperta continuamente in modo da poter vedere quando questo fallisce si poteva connettersi al server che esegue il ECHO protocol da soli, piuttosto che dover isReachable() farlo per voi e leggere e scrivere i dati e attendere che a fallire .

+1

Hmm forse non ero chiaro nella mia domanda. Quello che a volte succede al mio sistema è che la mia connessione internet si interrompe per qualche secondo e tutte le connessioni si chiudono. Un secondo dopo tutto va bene. Voglio monitorare questo su base giornaliera, per rendere rapporti quanto spesso questo sta accadendo. – kresjer

+0

È possibile connettersi da soli a un server ECHO e continuare a inviare e leggere i dati; aggiunto questo alla risposta. –

+0

Se una connessione esistente è ancora aperta non ha nulla a che fare con 'isReachable()' qualunque. – EJP

0

È possibile eseguire il ping di una macchina ogni numero di secondi, e ciò sarebbe piuttosto accurato. Fai attenzione a non DOSarlo.

Un'altra alternativa sarebbe eseguire un piccolo server su una macchina remota e mantenere una connessione ad essa.

+0

Come sapresti quando sei disconnesso dal piccolo server? E un ** ** ** uso di Java è nei dispositivi mobili Android dove il ping costante e i keepalive sono una cattiva idea perché uccidono la batteria. – user316117

0

Probabilmente è più semplice connettersi a yahoo/google o in un posto come questo.

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

Neil

+0

Niente da fare se una connessione esistente è ancora aperta. – EJP

+0

La domanda era come scrivere un "programma Java che monitora la mia connessione internet" che andrà bene. Java direttamente non può monitorare se la connessione con stucco è persa, ma dirà quando si verifica un problema di rete generico. È possibile chiamare "netstat" da java per monitorare una connessione di rete da un altro processo. –

+0

I programmatori Windows che utilizzano WinSock possono registrarsi per un evento. Questo si accende anche dopo aver scollegato un cavo. (con qualche secondo di ritardo) [https://stackoverflow.com/questions/44681648/in-android-how-can-i-receive-an-event-when-my-socket-closes-or-disconnects](link) – user316117

1

Si potrebbe desiderare di provare a guardare la presa timeout interval. Con un breve timeout (I credi che sia il valore predefinito è 'timeout infinito'), potresti essere in grado di intercettare un'eccezione o qualcosa quando l'host diventa irraggiungibile.

+1

Questo non rileva tutti i casi. Devi leggere o scrivere qualcosa sul socket. – tputkonen

10

Anche se TCP/IP è un protocollo "orientato alla connessione", in genere nessun dato viene inviato su una connessione inattiva. È possibile avere un socket aperto per un anno senza un singolo bit inviato dallo stack IP. Per notare che una connessione è andata persa, devi inviare alcuni dati a livello di applicazione. (*) Puoi provare questo scollegando il cavo telefonico dal tuo modem ADSL. Tutte le connessioni nel PC dovrebbero rimanere attive, a meno che le applicazioni non abbiano un qualche tipo di meccanismo keepalive a livello di applicazione.

Quindi l'unico modo per notare la connessione persa è aprire la connessione TCP ad alcuni server e leggere alcuni dati da esso. Forse il modo più semplice potrebbe essere quello di connettersi ad alcuni server FTP e recuperare un piccolo file - o elenco di directory - una volta ogni tanto. Non ho mai visto un server generico che fosse realmente destinato a essere utilizzato per questo caso, e ai proprietari del server FTP potrebbero non piacere i client che lo fanno.

(*) V'è anche un meccanismo chiamato TCP keepalive ma in molti sistemi operativi è necessario attivare per tutte le applicazioni, e non è molto pratica da usare se si vuole notare perdita di connessione in modo rapido

1

Ok così ho finalmente capito di lavoro 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(); 
} 

non pulite come speravo, ma non sta funzionando se lascio i os.writeBytes().

+17

Questo è qualcosa che non dovresti assolutamente usare. Può quasi essere considerato un attacco DOS contro stackoverflow.com! – tputkonen

+0

Un modo più semplice per farlo sarebbe quello di ospitare una semplice pagina/script su un host web che (probabilmente) non dispiacerebbe a un carico costante come questo, specialmente se la pagina renderizzata era piccola (solo una semplice "h" farebbe). Questo dovrebbe fornire una piccola impronta di piede e se le chiamate vengono effettuate ogni secondo circa il server probabilmente non si impantanerà risultando in un DOS. In teoria comunque. – Kingsolmn

+4

Questo non ha senso. Chiamare disponibile() di solito è inutile, chiamarlo e buttare via il risultato in modo definitivo. Il sonno è letteralmente una perdita di tempo. Questa tecnica non apporta proprio nulla. – EJP

4

Se il client si disconnette correttamente, un read() restituirà -1, restituisce null, readXXX() per qualsiasi altro X throw EOFException. L'unico modo affidabile per rilevare una connessione TCP persa è scrivere su di esso. Alla fine, quindi, verrà generato un "reset di connessione" IOException, ma occorrono almeno due scritture a causa del buffering.

1

Il metodo isConnected() all'interno della classe Socket.java è un po 'fuorviante. Non ti dice se il socket è attualmente connesso ad un host remoto (come se non fosse chiuso). Invece, ti dice se il socket è mai stato collegato a un host remoto. Se il socket è stato in grado di connettersi all'host remoto, questo metodo restituisce true, anche dopo che il socket è stato chiuso. Per sapere se un socket è attualmente aperto, è necessario verificare che isConnected() restituisca true e isClosed() restituisca false. Ad esempio:

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

_Per dire se un socket è attualmente aperto, è necessario verificare che isConnected() restituisca true e isClosed() restituisca false_ Questo non sembra essere vero. Vedi: [https://stackoverflow.com/questions/44685374/why-am-i-sending-an-rst-if-my-socket-is-connected-and-not-closed] (link) – user316117

+0

@ user316117 che la domanda non è chiara ma se isClosed è FALSE e isConnected è TRUE significa che sei riuscito a connetterti e la connessione non è mai stata chiusa. Se pensi di essere disconnesso e "isClosed()" restituisce FALSE, hai scoperto un bug JDK. Vedere questa documentazione: https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#isConnected-- – Alboz

+0

@Alboz Significa che sei riuscito a connetterti e che * socket * non ha stato chiuso ancora. Non ha nulla a che fare con la connessione, come hai affermato tu stesso nella tua risposta. Non c'è alcun bug JDK a meno che non si sia chiuso il proprio socket e poi si sia ottenuto 'isClosed() == false'. – EJP

Problemi correlati