2009-06-09 9 views
22

Kiedy używam, np. PuTTY i moje połączenie zostanie utracone (lub kiedy wykonuję instrukcję ipconfig /release w systemie Windows), odpowiada bezpośrednio i powiadamia o utracie połączenia.Wykrywanie utraconego połączenia Java

Chcę utworzyć program w języku Java, który monitoruje moje połączenie z Internetem (do pewnego niezawodnego serwera), aby rejestrować datę/czas, kiedy mój internet zawiedzie.

Próbowałem użyć metody Socket.isConnected(), ale to po prostu na zawsze powróci "prawda". Jak mogę to zrobić w Javie?

Odpowiedz

18

Najlepszym sposobem na stwierdzenie, czy połączenie zostało przerwane, jest próba odczytu/zapisu z gniazda. Jeśli operacja się nie powiedzie, straciłeś połączenie.

Wszystko, co musisz zrobić, to spróbować odczytać w pewnym przedziale, a jeśli odczyt się nie powiedzie, spróbuj ponownie się połączyć.

Ważne zdarzenia będą dla Ciebie, gdy odczyt się nie powiedzie - utracisz połączenie, a gdy nowe gniazdo zostanie podłączone - odzyskasz połączenie.

W ten sposób można śledzić czas przestojów.

+0

Nie zgadza się. Jeśli ustawiłeś limit czasu odczytu i uruchomi się wyjątek, to znaczy operacja się nie powiedzie, ale niekoniecznie oznacza utracone połączenie. – EJP

+2

@EJP To nie zawsze jest poprawne, ale daje dobre pojęcie o tym, co się dzieje. – jjnguy

+11

Nie, nie będzie. Nie można rozróżnić między wolnym serwerem a utraconym połączeniem z czasem oczekiwania na odczyt. – EJP

7

Dlaczego nie stosować metody isReachable() klasy java.net.InetAddress?

Jak to działa jest wdrożenie JVM specyficzny ale:

Typowa implementacja użyje żądań ICMP Echo, czy uprawnienia można uzyskać w inny sposób będzie starał się nawiązać połączenia TCP na porcie 7 (ECHO) z docelowy host.

Jeśli chcesz zachować połączenie otwarte nieustannie, dzięki czemu można zobaczyć, kiedy to nie można połączyć się z serwerem, uruchamiając ECHO protocol siebie zamiast isReachable() zrobi to za ciebie i odczytywać i zapisywać dane i czekać na to, aby nie .

+1

Hmm może nie było jasne w moim pytaniu. Czasem zdarza się, że mój internet opada na kilka sekund i wszystkie połączenia są zamknięte. Sekundę później wszystko jest w porządku. Chcę monitorować to codziennie, aby sporządzać raporty, jak często to się dzieje. – kresjer

+0

Możesz sam połączyć się z serwerem ECHO i kontynuować wysyłanie i czytanie danych; dodał to do odpowiedzi. –

+0

To, czy istniejące połączenie jest nadal otwarte, nie ma nic wspólnego z 'isReachable()' w ogóle. – EJP

0

Można pingować maszynę co kilka sekund, a to byłoby całkiem dokładne. Uważaj, aby tego nie zrobić.

Inną alternatywą byłoby uruchomienie małego serwera na zdalnym komputerze i utrzymanie połączenia z nim.

+0

Skąd wiesz, kiedy odłączyłeś się od małego serwera? I ** główne ** wykorzystanie Java jest w urządzeniach mobilnych z Androidem, gdzie stałe pingowanie i keepalives to zły pomysł, ponieważ zabijają baterię. – user316117

0

Jest to prawdopodobnie łatwiejsze połączenie z Yahoo/Google lub w innym miejscu.

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

Neil

+0

Nie ma nic wspólnego z tym, czy istniejące połączenie jest nadal otwarte. – EJP

+0

Pytanie brzmiało, jak napisać "program Java, który monitoruje moje połączenie internetowe", co będzie dobrze. Java nie może bezpośrednio monitorować, czy połączenie z kitami zostanie utracone, ale powie, kiedy wystąpi ogólny problem z siecią. Możesz wywołać "netstat" z java, aby monitorować połączenie sieciowe z innego procesu. –

+0

Programiści Windows używający WinSock mogą zarejestrować się na wydarzenie. Wystrzeliwuje to nawet po odłączeniu kabla. (z kilkuminutowym opóźnieniem) [https://stackoverflow.com/questions/44681648/in-android-how-can-i-receive-an-event-when-my-socket-closes-lub-disconnects](link) – user316117

1

Możecie spróbować patrząc na gniazdka timeout interval. Z krótkim czasem oczekiwania (I wierzymy, że domyślnie jest to "nieskończony czas oczekiwania"), wówczas możliwe jest zatrzymanie wyjątku lub czegoś, gdy host staje się nieosiągalny.

+1

To nie wykrywa wszystkich przypadków. Musisz coś przeczytać lub napisać do gniazda. – tputkonen

10

Mimo że protokół TCP/IP jest protokołem "zorientowanym na połączenie", zwykle żadne dane nie są wysyłane przez bezczynne połączenie. Możesz mieć gniazdo otwarte przez rok bez jednego bitu przesyłanego przez stos IP. Aby zauważyć, że połączenie zostało utracone, musisz wysłać pewne dane na poziomie aplikacji. (*) Możesz wypróbować to przez odłączenie kabla telefonicznego od modemu ADSL. Wszystkie połączenia na twoim komputerze powinny pozostać w górze, chyba że aplikacje mają jakiś mechanizm utrzymywania poziomu aplikacji.

Jedynym sposobem zauważenia utraconego połączenia jest otwarcie połączenia TCP z jakimś serwerem i odczytanie z niego pewnych danych. Być może najprostszym sposobem może być połączenie się z jakimś serwerem FTP i pobranie małego pliku - lub wykazu katalogów - raz na jakiś czas. Nigdy nie widziałem generycznego serwera, który naprawdę miał być używany w tej sprawie, a właściciele serwera FTP mogą nie lubić klientów robiących to.

(*) Istnieje również mechanizm zwany TCP keepalive ale w wielu systemów operacyjnych trzeba uaktywnić ją dla wszystkich aplikacji, a to naprawdę nie jest praktyczny w użyciu, jeśli chcesz zauważyć utratę połączenia szybko

1

Ok więc w końcu dostał pracę z

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(); 
} 

nie tak czysty, jak miałem nadzieję, ale to nie działa, jeśli pominąć os.writeBytes().

+17

Jest to coś, czego zdecydowanie nie powinieneś używać. Można go niemal uznać za atak DOS przeciwko stackoverflow.com! – tputkonen

+0

Bardziej przyjaznym sposobem na zrobienie tego byłoby hostowanie prostej strony/skryptu na hoście internetowym, który (prawdopodobnie) nie miałby nic przeciwko takiemu stałemu obciążeniu, zwłaszcza jeśli renderowana strona była mała (wystarczyłaby zwykła "h")). Powinno to zapewnić wydruk małej stopy, a jeśli połączenia są wykonywane co sekundę, serwer prawdopodobnie nie będzie się tłoczył, czego rezultatem będzie DOS. Teoretycznie. – Kingsolmn

+4

To nonsens. Wywoływanie dostępne() jest zwykle bezcelowe, a wywołanie go i odrzucenie wyniku zdecydowanie tak. Sen jest dosłownie stratą czasu. Ta technika nie wykonuje dokładnie nic. – EJP

4

Jeśli klient prawidłowo rozłączy się, read() zwróci -1, readLine() zwróci wartość null, readXXX() dla każdego innego X wyrzuca EOFException. Jedynym niezawodnym sposobem wykrywania utraconego połączenia TCP jest zapisywanie do niego. Ostatecznie spowoduje to "reset połączenia" IOException, ale wymaga co najmniej dwóch zapisów z powodu buforowania.

1

Metoda isConnected() w klasie Socket.java jest nieco myląca. Nie informuje o tym, czy gniazdo jest obecnie podłączone do zdalnego hosta (tak jakby nie było zamknięte). Zamiast tego informuje, czy gniazdo zostało kiedykolwiek podłączone do zdalnego hosta. Jeśli gniazdo mogło w ogóle połączyć się ze zdalnym hostem, ta metoda zwraca true, nawet po zamknięciu tego gniazda. Aby sprawdzić, czy gniazdo jest obecnie otwarte, należy sprawdzić, czy isConnected() zwraca true i isClosed() zwraca false. Na przykład:

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

_Aby powiedzieć, czy gniazdo jest obecnie otwarte, musisz sprawdzić, czy jest on połączony() zwraca wartość true i jest zamknięty() zwraca fałsz_. Nie wygląda to na prawdę. Zobacz: [https://stackoverflow.com/questions/44685374/why-am-i-sending-an-rst-if-my-socket-is-connected-and-not-closed] (link) – user316117

+0

@ user316117 that Pytanie nie jest jasne, ale jeśli isClosed jest FALSE, a isConnected ma wartość TRUE, oznacza to, że udało ci się połączyć i połączenie nigdy nie zostało zamknięte. Jeśli uważasz, że jesteś rozłączony i "isClosed()" zwraca FALSE, to odkryłeś błąd JDK. Zobacz tę dokumentację: https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#isConnected-- – Alboz

+0

@Alboz Oznacza to, że udało ci się połączyć, a * gniazdo * nie ma został już zamknięty. Nie ma to nic wspólnego z połączeniem, o czym sam mówiłeś w swojej odpowiedzi. Nie ma błędu JDK, dopóki nie zamkniesz własnego gniazda, a następnie otrzymasz 'isClosed() == false'. – EJP

Powiązane problemy