为什么InetAddress。可达的返回错误,我什么时候可以ping IP地址?

时间:2022-09-16 13:26:26
    InetAddress byName = InetAddress.getByName("173.39.161.140");
    System.out.println(byName);
    System.out.println(byName.isReachable(1000));

Why does isReachable return false? I can ping the IP.

为什么可及返回为假?我可以ping IP。

8 个解决方案

#1


67  

The "isReachable" method has not been worthy of using for me in many cases. You can scroll to the bottom to see my alternative for simply testing if you're online and capable of resolving external hosts (i.e. google.com) ... Which generally seems to work on *NIX machines.

在许多情况下,“可达”方法不值得我使用。如果你在线并且能够解析外部主机(例如google。com),你可以滚动到底部来查看我的选择。它通常在*NIX机器上运行。

The issue

这个问题

There is alot of chatter about this :

关于这一点有很多议论:

Part 1 : A reproducible example of the problem

第1部分:问题的可再现示例

Note that in this case, it fails.

注意,在这种情况下,它失败了。

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

Part 2 : A Hackish Workaround

第二部分:陈腐的变通方法

As an alternative, you can do this :

作为替代选择,你可以这样做:

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

The -c option of ping will allow ping to simply try to reach the server once(as opposed to the infinite ping which we're used to using at the terminal).

ping的-c选项允许ping尝试一次到达服务器(与我们在终端上使用的无限ping不同)。

This will return 0 if the host is reachable. Otherwise, you will get "2" as a return value.

如果主机是可达的,则返回0。否则,您将得到“2”作为返回值。

Much simpler - but of course it is platform specific. And there may be certain privilege caveats to using this command - but I find it works on my machines.

更简单——当然它是特定于平台的。使用这个命令可能有一些特权需要注意——但是我发现它在我的机器上工作。


PLEASE Note that : 1) This solution is not production quality. Its a bit of a hack. If google is down, or your internet is temporarily slow, or maybe even if there is some funniness in your privileges/system settings, if could return false negatives (i.e. it could fail even though the input address is reachable). 2) The isReachable failure is an outstanding issue. Again - there are several online resources indicating that there is no "perfect" way of doing this at the time of this writing, due to the way the JVM tries to reach hosts - I guess it is an intrinsically platform specific task which, although simple, hasn't yet been abstracted sufficiently by the JVM.

请注意:1)此解决方案不是生产质量。这是一个小技巧。如果谷歌关闭,或者您的internet暂时变慢,或者即使您的特权/系统设置中有一些有趣的内容,如果可能返回假否定(例如,即使输入地址是可达的,它也可能失败)。2)可达故障是一个突出的问题。——有几个在线资源表明没有“完美”的方法在撰写本文时,由于JVM的方式试图达到主机——我想这是一个本质上平台特定的任务,虽然简单,但尚未充分抽象JVM。

#2


31  

I came here to get an answer for this same question, but I was unsatisfied by any of the answers because I was looking for a platform independent solution. Here is the code which I wrote and is platform independent, but requires information about any open port on the other machine (which we have most of the time).

我来这里是为了得到这个问题的答案,但是我对任何一个答案都不满意,因为我正在寻找一个平*立的解决方案。这是我编写的代码,是独立于平台的,但是需要关于另一台机器上的任何开放端口的信息(我们大多数时候都有)。

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

#3


7  

If you only want to check if it is connected to internet use this method , It returns true if internet is connected, Its preferable if you use the address of the site you are trying to connect through the program.

如果您只想检查它是否连接到internet,请使用此方法,如果连接到internet,则返回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;
    }

#4


2  

Just mentioning it explicitly since the other answers don't. The ping part of isReachable() requires root access on Unix. And as pointed out by bestsss in 4779367:

只是明确地提到它,因为其他答案没有。isreavailable()的ping部分需要Unix上的根访问。正如在4779367年的bestsss所指出的:

And if you ask why ping from bash doesn't, actually it does need as well. Do that ls -l /bin/ping.

如果你问为什么bash中的ping没有,实际上它也需要。用ls -l / 2 / ping来做。

Since using root was not an option in my case the solution was to allow access to port 7 in the firewall to the specific server I was interested in.

因为在我的情况下,使用root不是一个选项,所以解决方案是允许访问防火墙中的端口7到我感兴趣的特定服务器。

#5


1  

I am not sure what was the state when the original question was asked back in 2012.

我不确定最初的问题在2012年被问到的时候是什么州。

As it stands now, ping will be executed as a root. Through the ping executable's authorization you will see the +s flag, and the process belonging to root, meaning it will run as root. run ls -liat on where the ping is located and you should see it.

现在,ping将作为根执行。通过ping可执行文件的授权,您将看到+s标志,以及属于根的进程,这意味着它将作为根运行。在ping位于的位置上运行ls -liat,您应该会看到它。

So, if you run InetAddress.getByName("www.google.com").isReacheable(5000) as root, it should return true.

因此,如果您运行InetAddress.getByName(“www.google.com”). isreach(5000)作为根,它应该返回true。

you need proper authorizations for the raw socket, which is used by ICMP (the protocol used by ping)

您需要对原始套接字进行适当的授权,这是ICMP使用的(ping使用的协议)

InetAddress.getByName is as reliable as ping, but you need proper permissions on the process to have it running properly.

InetAddress。getByName与ping一样可靠,但是您需要进程的适当权限才能使它正常运行。

#6


0  

I would suggest that the ONLY reliable way to test an internet connection is to actually connect AND download a file, OR to parse the output of an OS ping call via exec(). You cannot rely on the exit code for ping and isReachable() is crap.

我认为测试internet连接的唯一可靠方法是实际连接和下载文件,或者通过exec()解析OS ping调用的输出。您不能依赖于ping的退出代码,isreavailability()就是垃圾。

You cannot rely on a ping exit code as it returns 0 if the ping command executes correctly. Unfortunately, ping executes correctly if it can't reach the target host but gets a "Destination host unreachable" from your home ADSL router. This is kind of a reply that gets treated as a successfull hit, thus exit code = 0. Have to add though that this is on a Windows system. Not checked *nixes.

如果ping命令执行正确,则不能依赖于ping退出代码,因为它返回0。不幸的是,如果ping不能到达目标主机,但是从您的家庭ADSL路由器获得一个“无法到达目的地主机”,那么ping将正确执行。这是一种被视为成功命中的应答,因此退出代码= 0。必须补充的是,这是在Windows系统上。不* nix检查。

#7


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 is number of try to ping ip(packets), if you have busy network or systems choose biger nping numbers.
wping is time waiting for pong from ip, you can set it 2000ms
for using this method u can write this:

nping是尝试ping ip(数据包)的次数,如果你有繁忙的网络或系统选择biger nping号码。wping是等待ip pong的时间,你可以设置为2000ms使用这个方法u可以这样写:

isReachable(5, 2000, "192.168.7.93");

#8


-1  

Since you can ping the computer, your Java process should run with sufficient privileges to perform the check. Probably due to use of ports in the lower range. If you run your java program with sudo/superuser, I'll bet it works.

由于可以对计算机进行ping操作,所以Java进程应该具有足够的权限来执行检查。可能是由于使用了较低范围的端口。如果您使用sudo/superuser来运行java程序,我敢打赌它是有效的。

#1


67  

The "isReachable" method has not been worthy of using for me in many cases. You can scroll to the bottom to see my alternative for simply testing if you're online and capable of resolving external hosts (i.e. google.com) ... Which generally seems to work on *NIX machines.

在许多情况下,“可达”方法不值得我使用。如果你在线并且能够解析外部主机(例如google。com),你可以滚动到底部来查看我的选择。它通常在*NIX机器上运行。

The issue

这个问题

There is alot of chatter about this :

关于这一点有很多议论:

Part 1 : A reproducible example of the problem

第1部分:问题的可再现示例

Note that in this case, it fails.

注意,在这种情况下,它失败了。

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

Part 2 : A Hackish Workaround

第二部分:陈腐的变通方法

As an alternative, you can do this :

作为替代选择,你可以这样做:

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

The -c option of ping will allow ping to simply try to reach the server once(as opposed to the infinite ping which we're used to using at the terminal).

ping的-c选项允许ping尝试一次到达服务器(与我们在终端上使用的无限ping不同)。

This will return 0 if the host is reachable. Otherwise, you will get "2" as a return value.

如果主机是可达的,则返回0。否则,您将得到“2”作为返回值。

Much simpler - but of course it is platform specific. And there may be certain privilege caveats to using this command - but I find it works on my machines.

更简单——当然它是特定于平台的。使用这个命令可能有一些特权需要注意——但是我发现它在我的机器上工作。


PLEASE Note that : 1) This solution is not production quality. Its a bit of a hack. If google is down, or your internet is temporarily slow, or maybe even if there is some funniness in your privileges/system settings, if could return false negatives (i.e. it could fail even though the input address is reachable). 2) The isReachable failure is an outstanding issue. Again - there are several online resources indicating that there is no "perfect" way of doing this at the time of this writing, due to the way the JVM tries to reach hosts - I guess it is an intrinsically platform specific task which, although simple, hasn't yet been abstracted sufficiently by the JVM.

请注意:1)此解决方案不是生产质量。这是一个小技巧。如果谷歌关闭,或者您的internet暂时变慢,或者即使您的特权/系统设置中有一些有趣的内容,如果可能返回假否定(例如,即使输入地址是可达的,它也可能失败)。2)可达故障是一个突出的问题。——有几个在线资源表明没有“完美”的方法在撰写本文时,由于JVM的方式试图达到主机——我想这是一个本质上平台特定的任务,虽然简单,但尚未充分抽象JVM。

#2


31  

I came here to get an answer for this same question, but I was unsatisfied by any of the answers because I was looking for a platform independent solution. Here is the code which I wrote and is platform independent, but requires information about any open port on the other machine (which we have most of the time).

我来这里是为了得到这个问题的答案,但是我对任何一个答案都不满意,因为我正在寻找一个平*立的解决方案。这是我编写的代码,是独立于平台的,但是需要关于另一台机器上的任何开放端口的信息(我们大多数时候都有)。

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

#3


7  

If you only want to check if it is connected to internet use this method , It returns true if internet is connected, Its preferable if you use the address of the site you are trying to connect through the program.

如果您只想检查它是否连接到internet,请使用此方法,如果连接到internet,则返回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;
    }

#4


2  

Just mentioning it explicitly since the other answers don't. The ping part of isReachable() requires root access on Unix. And as pointed out by bestsss in 4779367:

只是明确地提到它,因为其他答案没有。isreavailable()的ping部分需要Unix上的根访问。正如在4779367年的bestsss所指出的:

And if you ask why ping from bash doesn't, actually it does need as well. Do that ls -l /bin/ping.

如果你问为什么bash中的ping没有,实际上它也需要。用ls -l / 2 / ping来做。

Since using root was not an option in my case the solution was to allow access to port 7 in the firewall to the specific server I was interested in.

因为在我的情况下,使用root不是一个选项,所以解决方案是允许访问防火墙中的端口7到我感兴趣的特定服务器。

#5


1  

I am not sure what was the state when the original question was asked back in 2012.

我不确定最初的问题在2012年被问到的时候是什么州。

As it stands now, ping will be executed as a root. Through the ping executable's authorization you will see the +s flag, and the process belonging to root, meaning it will run as root. run ls -liat on where the ping is located and you should see it.

现在,ping将作为根执行。通过ping可执行文件的授权,您将看到+s标志,以及属于根的进程,这意味着它将作为根运行。在ping位于的位置上运行ls -liat,您应该会看到它。

So, if you run InetAddress.getByName("www.google.com").isReacheable(5000) as root, it should return true.

因此,如果您运行InetAddress.getByName(“www.google.com”). isreach(5000)作为根,它应该返回true。

you need proper authorizations for the raw socket, which is used by ICMP (the protocol used by ping)

您需要对原始套接字进行适当的授权,这是ICMP使用的(ping使用的协议)

InetAddress.getByName is as reliable as ping, but you need proper permissions on the process to have it running properly.

InetAddress。getByName与ping一样可靠,但是您需要进程的适当权限才能使它正常运行。

#6


0  

I would suggest that the ONLY reliable way to test an internet connection is to actually connect AND download a file, OR to parse the output of an OS ping call via exec(). You cannot rely on the exit code for ping and isReachable() is crap.

我认为测试internet连接的唯一可靠方法是实际连接和下载文件,或者通过exec()解析OS ping调用的输出。您不能依赖于ping的退出代码,isreavailability()就是垃圾。

You cannot rely on a ping exit code as it returns 0 if the ping command executes correctly. Unfortunately, ping executes correctly if it can't reach the target host but gets a "Destination host unreachable" from your home ADSL router. This is kind of a reply that gets treated as a successfull hit, thus exit code = 0. Have to add though that this is on a Windows system. Not checked *nixes.

如果ping命令执行正确,则不能依赖于ping退出代码,因为它返回0。不幸的是,如果ping不能到达目标主机,但是从您的家庭ADSL路由器获得一个“无法到达目的地主机”,那么ping将正确执行。这是一种被视为成功命中的应答,因此退出代码= 0。必须补充的是,这是在Windows系统上。不* nix检查。

#7


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 is number of try to ping ip(packets), if you have busy network or systems choose biger nping numbers.
wping is time waiting for pong from ip, you can set it 2000ms
for using this method u can write this:

nping是尝试ping ip(数据包)的次数,如果你有繁忙的网络或系统选择biger nping号码。wping是等待ip pong的时间,你可以设置为2000ms使用这个方法u可以这样写:

isReachable(5, 2000, "192.168.7.93");

#8


-1  

Since you can ping the computer, your Java process should run with sufficient privileges to perform the check. Probably due to use of ports in the lower range. If you run your java program with sudo/superuser, I'll bet it works.

由于可以对计算机进行ping操作,所以Java进程应该具有足够的权限来执行检查。可能是由于使用了较低范围的端口。如果您使用sudo/superuser来运行java程序,我敢打赌它是有效的。