web-dev-qa-db-ja.com

IPアドレスをpingできるのに、なぜInetAddress.isReachableがfalseを返すのですか?

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

isReachablefalseを返すのはなぜですか? IPをpingできます。

89
jiafu

"isReachable"メソッドは、多くの場合に使用する価値がありませんでした。一番下までスクロールして、オンラインで外部ホスト(google.comなど)を解決できるかどうかを簡単にテストするための代替案を確認できます...これは、一般的に* NIXマシンで動作するようです。

問題

これについてはたくさんのおしゃべりがあります:

パート1:問題の再現可能な例

この場合、失敗することに注意してください。

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

パート2:ハックの回避策

別の方法として、これを行うことができます:

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

pingの-cオプションを使用すると、(端末で使用する無限のpingとは対照的に)pingがサーバーに1回到達するだけで済みます。

これは、ホストが到達可能であれば0を返します。それ以外の場合、戻り値として「2」を取得します。

はるかに単純ですが、もちろんプラットフォーム固有です。また、このコマンドの使用には特定の特権の警告があるかもしれません-しかし、私はそれが私のマシンで動作することがわかります。


注意してください:1)このソリューションは生産品質ではありません。ちょっとしたハックです。グーグルがダウンしている場合、またはインターネットが一時的に低速である場合、または権限/システム設定に何らかの面白いところがある場合でも、偽陰性を返す可能性があります(つまり、入力アドレスに到達しても失敗する可能性があります)。 2)isReachableの失敗は未解決の問題です。繰り返しますが、JVMがホストに到達しようとする方法のため、この記事の執筆時点でこれを行う「完璧な」方法がないことを示すいくつかのオンラインリソースがあります。 、まだJVMによって十分に抽象化されていません。

71
jayunit100

私はこの同じ質問の答えを得るためにここに来ましたが、プラットフォームに依存しないソリューションを探していたため、どの答えにも不満でした。これは私が書いた、プラットフォームに依存しないコードですが、他のマシンで開いているポートについての情報が必要です(ほとんどの場合)。

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;
    }
}
47
Sourabh Bhat

インターネットに接続されているかどうかだけを確認したい場合は、このメソッドを使用します。インターネットが接続されている場合はtrueを返します。プログラムを介して接続しようとしているサイトのアドレスを使用する場合.

     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;
    }
7
CleanX

他の答えにはないので、明示的に言及してください。 isReachable()のping部分には、Unixのルートアクセスが必要です。そして 4779367 のbestsssで指摘されているように:

そして、なぜbashからのpingがそうしないのかと尋ねると、実際には同様に必要です。 ls -l/bin/pingを実行します。

私の場合、ルートの使用はオプションではなかったので、解決策は、関心のある特定のサーバーへのファイアウォールのポート7へのアクセスを許可することでした。

2
Zitrax

2012年に元の質問が返されたときの状態はわかりません。

現在のところ、pingはルートとして実行されます。 ping実行可能ファイルの認証により、+ sフラグと、rootに属するプロセスが表示されます。つまり、rootとして実行されます。 pingがある場所でls -liatを実行すると、表示されるはずです。

そのため、ルートとしてInetAddress.getByName( "www.google.com")。isReacheable(5000)を実行すると、trueが返されます。

iCMP(pingで使用されるプロトコル)で使用されるrawソケットに適切な承認が必要です。

InetAddress.getByNameはpingと同じくらい信頼性がありますが、正常に実行するにはプロセスの適切な権限が必要です。

2
Clebert Suconic

インターネット接続をテストする唯一の信頼できる方法は、実際に接続してファイルをダウンロードし、OR exec()を介してOS ping呼び出しの出力を解析することです。 pingの終了コードに依存することはできず、isReachable()はがらくたです。

Pingコマンドが正しく実行されると0を返すため、ping終了コードに依存することはできません。残念ながら、ターゲットホストに到達できないが、ホームADSLルーターから「宛先ホストに到達できません」を取得した場合、pingは正しく実行されます。これは一種の応答であり、成功したヒットとして扱われるため、終了コード= 0です。これはWindowsシステム上にあることを追加する必要があります。チェックなし* nixes。

0
cossoft
 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は、ネットワークまたはシステムがビジーな場合に、より大きなnping番号を選択した場合に、ip(packets)にpingを試行する回数です。
wpingはipからのポンを待つ時間です。2000msに設定できます
この方法を使用する場合、次のように書くことができます。

isReachable(5, 2000, "192.168.7.93");
0
Armin Mokri

または、この方法を使用します:

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