Dlaczego InetAddress.isReachable zwraca false, kiedy mogę pingować adres IP?


96
InetAddress byName = InetAddress.getByName("173.39.161.140");
System.out.println(byName);
System.out.println(byName.isReachable(1000));

Dlaczego isReachablewraca false? Mogę pingować adres IP.



1
to jest podobne. ale nie mogę znaleźć żadnej wskazówki, jak rozwiązać problem, więc podniosłem go tutaj. Dziękuję za przypomnienie!
jiafu

2
Spróbowałbym zwiększyć limit czasu.
jayunit100

to bardzo dobre pytanie, nie ma wystarczającej liczby głosów pozytywnych. Jedyne podobne pytanie, które znalazłem, zostało oznaczone jako pytanie clojure, a odpowiedź nie była rozstrzygająca.
jayunit100

3
czy ktoś może mi powiedzieć, co dokładnie robi isReachable ()? zwraca mi fałsz nawet na lokalnym hoście ...
Seth Keno,

Odpowiedzi:


73

W wielu przypadkach metoda „isReachable” nie była warta zastosowania. Możesz przewinąć w dół, aby zobaczyć moją alternatywę dla prostego testowania, jeśli jesteś online i jesteś w stanie rozwiązać zewnętrzne hosty (np. Google.com) ... Co ogólnie wydaje się działać na maszynach * NIX.

Problem

Jest dużo gadania na ten temat:

Część 1: Odtwarzalny przykład problemu

Zauważ, że w tym przypadku nie powiedzie się.

       //also, this fails for an invalid address, like "www.sjdosgoogle.com1234sd" 
       InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
      for (InetAddress address : addresses) {
        if (address.isReachable(10000))
        {   
           System.out.println("Connected "+ address);
        }
        else
        {
           System.out.println("Failed "+address);
        }
      }
          //output:*Failed www.google.com/74.125.227.114*

Część 2: Obejście problemu hakerskiego

Alternatywnie możesz to zrobić:

// in case of Linux change the 'n' to 'c'
    Process p1 = java.lang.Runtime.getRuntime().exec("ping -n 1 www.google.com");
    int returnVal = p1.waitFor();
    boolean reachable = (returnVal==0);

Opcja -c polecenia ping pozwoli pingowi po prostu raz spróbować dotrzeć do serwera (w przeciwieństwie do nieskończonego polecenia ping, którego używamy na terminalu).

Zwróci to 0, jeśli host jest osiągalny . W przeciwnym razie zwrócona zostanie wartość „2”.

O wiele prostsze - ale oczywiście zależy to od platformy. Mogą istnieć pewne zastrzeżenia dotyczące uprawnień do używania tego polecenia - ale uważam, że działa na moich komputerach.


NALEŻY pamiętać, że: 1) To rozwiązanie nie jest jakością produkcji. To trochę hack. Jeśli Google nie działa lub Twój internet jest chwilowo wolny, a może nawet jeśli w Twoich uprawnieniach / ustawieniach systemu jest coś dziwnego, może zwrócić fałszywe negatywy (tj. Może się nie powieść, nawet jeśli adres wejściowy jest osiągalny). 2) Awaria isReachable jest nierozstrzygniętym problemem. Ponownie - istnieje kilka zasobów internetowych wskazujących, że w chwili pisania tego tekstu nie ma „idealnego” sposobu na zrobienie tego, ze względu na sposób, w jaki JVM próbuje dotrzeć do hostów - wydaje mi się, że jest to z natury zadanie specyficzne dla platformy, które chociaż proste , nie został jeszcze wystarczająco wyodrębniony przez JVM.


@ jayunit100, ponieważ żadne z podejść nie działa, z powodu isReachableniepowodzenia i użycia polecenia ping otrzymuję niedozwolone ICMP? Czy już wiesz, jak sobie z tym poradzić?
Yuvi,

6
@Yuvi Jeśli używasz systemu Windows, flagi są różne. Zamiast -c chcesz -n.
James T Snell

Funkcja waitFor () zwraca 10 sekund. Czy istnieje sposób, aby wspomnieć o przekroczeniu limitu czasu w Javie 7?
Jaydev,

@Jaydev, jest też przeciążona opcja: public boolean waitFor(long timeout, TimeUnit unit)w java.lang.Process (@since 1.8)
niepodzielne

Na dzień 2020-01 mogę uruchomić przykład problemu bez żadnych problemów, zgłasza „Połączono” dla jednego adresu IPv4 i jednego adresu IPv6. Bug jest również stałe w Java 5.0 B22. Może isReachablejest teraz bardziej niezawodny.
Lii

54

Przyszedłem tutaj, aby uzyskać odpowiedź na to samo pytanie, ale żadna z nich nie była satysfakcjonująca, ponieważ szukałem rozwiązania niezależnego od platformy. Oto kod, który napisałem i jest niezależny od platformy, ale wymaga informacji o dowolnym otwartym porcie na innym komputerze (który mamy przez większość czasu).

private static boolean isReachable(String addr, int openPort, int timeOutMillis) {
    // Any Open port on other machine
    // openPort =  22 - ssh, 80 or 443 - webserver, 25 - mailserver etc.
    try {
        try (Socket soc = new Socket()) {
            soc.connect(new InetSocketAddress(addr, openPort), timeOutMillis);
        }
        return true;
    } catch (IOException ex) {
        return false;
    }
}

2
To świetne rozwiązanie niezależne od platformy, dziękuję!
ivandov

1
Cieszę się, że tu trafiłem, fajny sposób myślenia Sourabh :)
JustADev

Tak więc, aby upewnić się, że całkowicie rozumiem: dopóki nie ma wyjątku, adres był osiągalny?
Timmiej93

1
Jest to identyczne z tym, co InetAddress.isReachable()już robi, przez port 7, z tym wyjątkiem, że ten ostatni jest bardziej inteligentny w kwestii tego, co różne możliwe IOExceptionsoznaczają pod względem osiągalności.
Markiz Lorne

1
Tak @EJP Myślę, że byłoby wspaniale, gdyby InetAddress.isReachable()został przeciążony, aby dołączyć argument portu do standardowej biblioteki. Zastanawiam się, dlaczego nie został uwzględniony?
Sourabh Bhat,

7

Jeśli chcesz tylko sprawdzić, czy jest podłączony do Internetu, użyj tej metody. Zwraca wartość true, jeśli internet jest podłączony. Najlepiej, jeśli używasz adresu witryny, z którą próbujesz się połączyć za pośrednictwem programu.

     public static boolean isInternetReachable()
    {
        try {
            //make a URL to a known source
            URL url = new URL("http://www.google.com");

            //open a connection to that source
            HttpURLConnection urlConnect = (HttpURLConnection)url.openConnection();

            //trying to retrieve data from the source. If there
            //is no connection, this line will fail
            Object objData = urlConnect.getContent();

        } catch (Exception e) {              
            e.printStackTrace();
            return false;
        }

        return true;
    }

2
Bezużyteczne, jeśli serwer nie ma serwera WWW, nie jest to w ogóle warunek określony w pytaniu.
Fran Marzoa

3

Wspominam o tym wyraźnie, ponieważ inne odpowiedzi nie. Część isReachable () zawierająca ping wymaga uprawnień administratora w systemie Unix. I jak wskazał bestsss w 4779367 :

A jeśli zapytasz, dlaczego ping z basha nie, w rzeczywistości też potrzebuje. Zrób to ls -l / bin / ping.

Ponieważ użycie roota nie wchodziło w grę w moim przypadku, rozwiązaniem było zezwolenie na dostęp do portu 7 w firewallu do konkretnego serwera, który mnie interesował.


3

Nie jestem pewien, jaki był stan, gdy zadawano pierwotne pytanie w 2012 roku.

W obecnej formie ping zostanie wykonany jako root. Po autoryzacji pliku wykonywalnego ping zobaczysz flagę + s i proces należący do roota, co oznacza, że ​​będzie działał jako root. uruchom ls -liat na miejscu, w którym znajduje się ping i powinieneś go zobaczyć.

Tak więc, jeśli uruchomisz InetAddress.getByName („www.google.com”). IsReacheable (5000) jako root, powinno zwrócić wartość true.

potrzebujesz odpowiednich uprawnień do gniazda raw, z którego korzysta ICMP (protokół używany przez ping)

InetAddress.getByName jest równie niezawodny jak ping, ale potrzebujesz odpowiednich uprawnień do procesu, aby działał poprawnie.


0

Sugerowałbym, że JEDYNYM niezawodnym sposobem przetestowania połączenia internetowego jest faktyczne połączenie I pobranie pliku LUB przeanalizowanie danych wyjściowych wywołania ping systemu operacyjnego za pośrednictwem exec (). Nie możesz polegać na kodzie zakończenia dla polecenia ping, a isReachable () to bzdura.

Nie można polegać na kodzie zakończenia polecenia ping, ponieważ zwraca on 0, jeśli polecenie ping zostanie wykonane poprawnie. Niestety, polecenie ping jest wykonywane poprawnie, jeśli nie może dotrzeć do hosta docelowego, ale otrzyma komunikat „Host docelowy nieosiągalny” z domowego routera ADSL. Jest to rodzaj odpowiedzi, która jest traktowana jako udane trafienie, więc kod zakończenia = 0. Muszę jednak dodać, że jest to system Windows. Niezaznaczone * nixes.


0
 private boolean isReachable(int nping, int wping, String ipping) throws Exception {

    int nReceived = 0;
    int nLost = 0;

    Runtime runtime = Runtime.getRuntime();
    Process process = runtime.exec("ping -n " + nping + " -w " + wping + " " + ipping);
    Scanner scanner = new Scanner(process.getInputStream());
    process.waitFor();
    ArrayList<String> strings = new ArrayList<>();
    String data = "";
    //
    while (scanner.hasNextLine()) {
        String string = scanner.nextLine();
        data = data + string + "\n";
        strings.add(string);
    }

    if (data.contains("IP address must be specified.")
            || (data.contains("Ping request could not find host " + ipping + ".")
            || data.contains("Please check the name and try again."))) {
        throw new Exception(data);
    } else if (nping > strings.size()) {
        throw new Exception(data);
    }

    int index = 2;

    for (int i = index; i < nping + index; i++) {
        String string = strings.get(i);
        if (string.contains("Destination host unreachable.")) {
            nLost++;
        } else if (string.contains("Request timed out.")) {
            nLost++;
        } else if (string.contains("bytes") && string.contains("time") && string.contains("TTL")) {
            nReceived++;
        } else {
        }
    }

    return nReceived > 0;
}

nping to liczba prób pingowania ip (pakietów), jeśli masz zajętą ​​sieć lub systemy, wybierz większe numery nping.
wping to czas oczekiwania na pong z ip, możesz ustawić go na 2000ms,
aby użyć tej metody, możesz napisać to:

isReachable(5, 2000, "192.168.7.93");

potencjalne wstrzyknięcie polecenia, upewnij się, że sprawdziłeś poprawność danych wejściowych przed uruchomieniem tego
szpieg

pojawia się również komunikat o błędzie „ogólny błąd”. To również wygląda na specyficzne dla systemu Windows. Jestem prawie pewien, że te komunikaty o błędach są zlokalizowane w różnych językach, więc nie są super przenośne.
szpieg

dotyczy to systemów Windows.
Armin Mokri

tak, widziałem to już wcześniej w
szpieg,

0

Lub używając w ten sposób:

public static boolean exists(final String host)
{
   try
   {
      InetAddress.getByName(host);
      return true;
   }
   catch (final UnknownHostException exception)
   {
      exception.printStackTrace();
      // Handler
   }
   return false;
}

0

InetAddress.isReachable jest flappy i czasami zwraca nieosiągalny dla adresów, które możemy pingować.

Wypróbowałem następujące:

ping -c 1 <fqdn>i sprawdź exit status.

Działa we wszystkich przypadkach, które wypróbowałem, gdzie InetAddress.isReachablenie działa.


-1

Ponieważ można pingować komputer, proces Java powinien działać z uprawnieniami wystarczającymi do wykonania sprawdzenia. Prawdopodobnie z powodu wykorzystania portów z dolnego zakresu. Jeśli uruchomisz program java z sudo / superuser, założę się, że działa.


Nie potrzebujesz uprawnień, aby łączyć się z portami o niskim zasięgu.
Markiz Lorne
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.