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

为什么isReachable返回false?我可以ping通IP。

4

12 回答 12

74

在很多情况下,“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 部分:Hackish 解决方法

作为替代方案,您可以这样做:

// 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 不同)。

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

简单得多 - 但当然它是特定于平台的。使用此命令可能有某些特权警告 - 但我发现它适用于我的机器。


请注意:1)此解决方案不是生产质量。它有点像黑客。如果谷歌关闭,或者您的互联网暂时变慢,或者即使您的权限/系统设置中有一些有趣的东西,如果可能会返回误报(即,即使输入地址可以访问,它也可能会失败)。2) isReachable 失败是一个突出的问题。再次 - 有几个在线资源表明在撰写本文时没有“完美”的方式来执行此操作,因为 JVM 尝试访问主机的方式 - 我想这是一个本质上特定于平台的任务,虽然很简单, 还没有被 JVM 充分抽象。

于 2012-04-13T17:40:30.517 回答
72

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

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

更新:根据最近对此答案的评论,这是上述代码的简洁版本:

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 (Socket soc = new Socket()) {
        soc.connect(new InetSocketAddress(addr, openPort), timeOutMillis);
        return true;
    } catch (IOException ex) {
        return false;
    }
}
于 2015-12-11T17:02:06.170 回答
7

如果您只想检查它是否已连接到互联网,请使用此方法,如果已连接互联网,则返回 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;
    }
于 2013-07-26T16:48:56.490 回答
4

只是明确提及它,因为其他答案没有。isReachable() 的 ping 部分需要 Unix 上的 root 访问权限。正如 bestsss 在4779367中指出的那样:

如果你问为什么 bash 的 ping 不需要,实际上它也需要。这样做 ls -l /bin/ping。

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

于 2013-12-10T08:52:54.523 回答
4

我不确定 2012 年最初的问题被问到时的状态是什么。

就目前而言,ping 将作为 root 执行。通过 ping 可执行文件的授权,您将看到 +s 标志,以及属于 root 的进程,这意味着它将以 root 身份运行。在 ping 所在的位置运行 ls -liat,您应该会看到它。

因此,如果您以 root 身份运行 InetAddress.getByName("www.google.com").isReachable(5000),它应该返回 true。

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

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

于 2016-09-28T21:12:09.887 回答
0

我建议测试互联网连接的唯一可靠方法是实际连接并下载文件,或者通过 exec() 解析 OS ping 调用的输出。您不能依赖 ping 的退出代码,并且 isReachable() 是废话。

您不能依赖 ping 退出代码,因为如果 ping 命令正确执行,它会返回 0。不幸的是,如果 ping 无法到达目标主机但从您的家庭 ADSL 路由器获得“目标主机无法访问”,则 ping 会正确执行。这是一种被视为成功命中的回复,因此退出代码 = 0。尽管这是在 Windows 系统上,但必须添加。未检查 *nixes。

于 2014-09-30T02:36:45.270 回答
0

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

于 2014-01-10T11:36:41.443 回答
0

或使用这种方式:

public static boolean exists(final String host)
{
   try
   {
      InetAddress.getByName(host);
      return true;
   }
   catch (final UnknownHostException exception)
   {
      exception.printStackTrace();
      // Handler
   }
   return false;
}
于 2019-01-18T08:52:32.850 回答
0

因为 isReachable 使用的是 TCP 协议(​​by WireShark) Ping 命令使用的是 ICMP 协议,如果要返回 true 则需要打开 7 端口

于 2021-03-14T08:57:18.933 回答
0

InetAddress.isReachable是轻飘飘的,有时对于我们可以 ping 的地址返回不可访问。

我尝试了以下方法:

ping -c 1 <fqdn>并检查exit status.

适用于我尝试过的所有情况都InetAddress.isReachable不起作用。

于 2019-10-30T08:40:41.160 回答
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 是尝试 ping ip(数据包)的数量,如果您的网络或系统繁忙,请选择更大的 nping 号码。
wping 是等待来自 ip 的 pong 的时间,您可以将其设置为 2000 毫秒
以使用此方法您可以这样写:

isReachable(5, 2000, "192.168.7.93");
于 2017-02-03T10:40:15.030 回答
0

检查互联网

public boolean isInternetAvailable() {
        try {
            InetAddress ipAddr = InetAddress.getByName("google.com");
            //You can replace it with your name
            return !ipAddr.equals("");

        } catch (Exception e1) {
            try {
                Process p1 = java.lang.Runtime.getRuntime().exec("/system/bin/ping  -W 1 -c 1 www.google.com");
                int returnVal = 0;
                returnVal = p1.waitFor();
                boolean reachable = (returnVal==0);
                return reachable;
            } catch (Exception e2) {
                e2.printStackTrace();
                return false;
            }
        }
    }

检查网络连接

private boolean isNetworkConnected() {
        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

        return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
    }
于 2021-02-04T14:55:55.753 回答