Warum gibt InetAddress.isReachable false zurück, wenn ich die IP-Adresse anpingen kann?


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

Warum kehrt isReachablezurück false? Ich kann die IP anpingen.



1
es ist ähnlich. Aber ich kann keinen Hinweis finden, um das Problem zu lösen. Also habe ich es hier wiederholt. Vielen Dank für Ihre Erinnerung!
Jiafu

2
Ich würde versuchen, das Timeout zu erhöhen.
Jayunit100

Das ist eine sehr gute Frage, es gibt nicht genug positive Stimmen. Die einzige ähnliche Frage, die ich gefunden habe, wurde als Clojure-Frage markiert und die Antwort war nicht schlüssig.
Jayunit100

2
Kann mir jemand sagen, was genau isReachable () macht? es gibt mich sogar auf localhost falsch zurück ...
Seth Keno

Antworten:


73

Die "isReachable" -Methode hat sich in vielen Fällen für mich nicht gelohnt . Sie können nach unten scrollen, um meine Alternative zum einfachen Testen zu sehen, ob Sie online sind und externe Hosts auflösen können (z. B. google.com). Dies scheint im Allgemeinen auf * NIX-Computern zu funktionieren.

Das Thema

Darüber wird viel geredet:

Teil 1: Ein reproduzierbares Beispiel für das Problem

Beachten Sie, dass dies in diesem Fall fehlschlägt.

       //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*

Teil 2: Eine hackige Problemumgehung

Alternativ können Sie dies tun:

// 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);

Mit der Ping- Option -c kann Ping einfach einmal versuchen, den Server zu erreichen (im Gegensatz zu dem unendlichen Ping, den wir am Terminal gewohnt sind).

Dies gibt 0 zurück, wenn der Host erreichbar ist . Andernfalls erhalten Sie "2" als Rückgabewert.

Viel einfacher - aber natürlich plattformspezifisch. Die Verwendung dieses Befehls kann mit gewissen Einschränkungen verbunden sein - aber ich finde, dass er auf meinen Computern funktioniert.


BITTE Beachten Sie Folgendes: 1) Diese Lösung entspricht nicht der Produktionsqualität. Es ist ein bisschen ein Hack. Wenn Google nicht verfügbar ist oder Ihr Internet vorübergehend langsam ist oder wenn Ihre Berechtigungen / Systemeinstellungen lustig sind, kann dies zu falschen Negativen führen (dh es kann fehlschlagen, obwohl die Eingabeadresse erreichbar ist). 2) Der isReachable-Fehler ist ein offenes Problem. Auch hier gibt es mehrere Online-Ressourcen, die darauf hinweisen, dass es zum Zeitpunkt des Schreibens keine "perfekte" Möglichkeit gibt, dies zu tun, da die JVM versucht, Hosts zu erreichen. Ich denke, es handelt sich um eine plattformspezifische Aufgabe, die zwar einfach ist , wurde von der JVM noch nicht ausreichend abstrahiert.


@ jayunit100 für keiner der Ansätze funktioniert, von isReachablemir werde ich gescheitert und mit Ping bekomme ich icmp nicht erlaubt? Wissen Sie, wie Sie jetzt damit umgehen sollen?
Yuvi

6
@Yuvi Wenn Sie Windows verwenden, unterscheiden sich die Flags. Anstelle von -c willst du -n.
James T Snell

waitFor () benötigt 10 Sekunden, um zurückzukehren. Gibt es eine Möglichkeit, Timeout in Java 7 zu erwähnen?
Jaydev

@ Jaydev, es gibt auch eine überladene Option: public boolean waitFor(long timeout, TimeUnit unit)in java.lang.Process (@since 1.8)
unteilbar

Ab 2020-01 kann ich das Beispiel des Problems ohne Probleme ausführen. Es meldet "Verbunden" für eine IPv4- und eine IPv6-Adresse. Der Fehler wurde auch in Java 5.0 b22 behoben. Vielleicht isReachableist jetzt Tage zuverlässiger.
Lii

54

Ich kam hierher, um eine Antwort auf dieselbe Frage zu erhalten, war jedoch mit keiner der Antworten zufrieden, da ich nach einer plattformunabhängigen Lösung suchte. Hier ist der Code, den ich geschrieben habe und der plattformunabhängig ist, aber Informationen über jeden offenen Port auf dem anderen Computer erfordert (den wir die meiste Zeit haben).

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
Dies ist eine großartige plattformunabhängige Lösung, danke!
ivandov

1
Ich bin froh, dass ich hier
gelandet

Also, nur um sicherzugehen, dass ich alles verstehe: Solange es keine Ausnahme gibt, war die Adresse erreichbar?
Timmiej93

1
Dies ist identisch mit dem, was InetAddress.isReachable()bereits über Port 7 geschieht, mit der Ausnahme, dass letzterer intelligenter ist, was die verschiedenen möglichen IOExceptionsin Bezug auf die Erreichbarkeit bedeuten.
Marquis von Lorne

1
Ja @EJP Ich denke, es wäre großartig, wenn InetAddress.isReachable()das Port-Argument in die Standardbibliothek aufgenommen würde. Ich frage mich, warum es nicht enthalten war?
Sourabh Bhat

7

Wenn Sie nur überprüfen möchten, ob eine Internetverbindung besteht, verwenden Sie diese Methode. Bei Internetverbindung wird true zurückgegeben. Dies ist vorzuziehen, wenn Sie die Adresse der Site verwenden, die Sie über das Programm verbinden möchten.

     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
Nutzlos, wenn der Server keinen Webserver hat, ist dies überhaupt keine in der Frage angegebene Bedingung.
Fran Marzoa

3

Ich erwähne es nur explizit, da die anderen Antworten dies nicht tun. Der Ping-Teil von isReachable () erfordert Root-Zugriff unter Unix. Und wie von bestsss in 4779367 hervorgehoben :

Und wenn Sie fragen, warum Ping von Bash nicht funktioniert, muss es auch so sein. Mach das ls -l / bin / ping.

Da die Verwendung von root in meinem Fall keine Option war, bestand die Lösung darin, den Zugriff auf Port 7 in der Firewall auf den bestimmten Server zuzulassen, an dem ich interessiert war.


3

Ich bin mir nicht sicher, wie der Stand war, als die ursprüngliche Frage 2012 gestellt wurde.

In der jetzigen Form wird Ping als Root ausgeführt. Durch die Autorisierung der ausführbaren Ping-Datei sehen Sie das Flag + s und den Prozess, der zu root gehört, was bedeutet, dass es als root ausgeführt wird. Führen Sie ls -liat aus, wo sich der Ping befindet, und Sie sollten ihn sehen.

Wenn Sie also InetAddress.getByName ("www.google.com"). IsReacheable (5000) als root ausführen, sollte true zurückgegeben werden.

Sie benötigen die entsprechenden Berechtigungen für den Raw-Socket, der von ICMP verwendet wird (das von Ping verwendete Protokoll).

InetAddress.getByName ist genauso zuverlässig wie Ping, aber Sie benötigen die entsprechenden Berechtigungen für den Prozess, damit er ordnungsgemäß ausgeführt wird.


0

Ich würde vorschlagen, dass der EINZIGE zuverlässige Weg zum Testen einer Internetverbindung darin besteht, eine Verbindung herzustellen UND eine Datei herunterzuladen ODER die Ausgabe eines Betriebssystem-Ping-Aufrufs über exec () zu analysieren. Sie können sich nicht auf den Exit-Code für Ping verlassen und isReachable () ist Mist.

Sie können sich nicht auf einen Ping-Exit-Code verlassen, da dieser 0 zurückgibt, wenn der Ping-Befehl korrekt ausgeführt wird. Leider wird Ping korrekt ausgeführt, wenn es den Zielhost nicht erreichen kann, aber einen "Zielhost nicht erreichbar" von Ihrem ADSL-Heimrouter erhält. Dies ist eine Art Antwort, die als erfolgreicher Treffer behandelt wird. Beenden Sie daher den Code = 0. Sie müssen jedoch hinzufügen, dass dies auf einem Windows-System erfolgt. Nicht geprüft * 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 ist die Anzahl der Versuche, IP (Pakete) zu pingen, wenn Sie ein ausgelastetes Netzwerk oder Systeme haben, wählen Sie größere nping-Nummern.
wping ist die Zeit, die auf pong von ip wartet. Sie können 2000 ms
für die Verwendung dieser Methode einstellen. Sie können Folgendes schreiben:

isReachable(5, 2000, "192.168.7.93");

Überprüfen Sie die Zeichenfolgeneingabe, bevor Sie diese
spionieren Sie den

Es gibt auch die Fehlermeldung "Allgemeiner Fehler". Dies sieht auch wie Windows-spezifisch aus. Ich bin mir ziemlich sicher, dass diese Fehlermeldungen in verschiedenen Sprachen lokalisiert sind, also nicht super portabel.
Spion

Dies ist für Windows-Systeme.
Armin Mokri

Ja, ich habe es schon einmal unter Windows gesehen
Spion

0

Oder auf folgende Weise:

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 ist flappy und gibt manchmal nicht erreichbare Adressen zurück, die wir anpingen können.

Ich habe folgendes versucht:

ping -c 1 <fqdn>und überprüfen Sie die exit status.

Funktioniert für alle Fälle, in denen ich versucht habe, wo InetAddress.isReachablees nicht funktioniert.


-1

Da Sie den Computer anpingen können, sollte Ihr Java-Prozess mit ausreichenden Berechtigungen ausgeführt werden, um die Überprüfung durchzuführen. Wahrscheinlich aufgrund der Verwendung von Ports im unteren Bereich. Wenn Sie Ihr Java-Programm mit sudo / superuser ausführen, funktioniert es bestimmt.


Sie benötigen keine Berechtigung, um eine Verbindung zu Ports im niedrigen Bereich herzustellen.
Marquis von Lorne
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.