为什么InetAddress.isReachable返回false时,我可以ping IP地址?

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

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

在许多情况下, “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)。

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

更简单 – 但当然这是平台特定的。 使用这个命令可能会有某些特权警告 – 但是我发现它可以在我的机器上运行。


请注意:1)此解决方案不是生产质量。 它有点黑客。 如果谷歌关闭,或者你的网络暂时很慢,或者甚至在你的权限/系统设置中有一些乐趣,如果可能返回错误的否定(即,即使输入地址可达也可能失败)。 2)isReachable失败是一个突出的问题。 再次 – 有几个在线资源表明,在撰写本文时,由于JVM尝试访问主机的方式,没有“完美”的方式来做这件事 – 我想这是一个固有的平台特定的任务,虽然简单,尚未被JVM充分抽象。

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

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

如果你只是想检查它是否连接到互联网使用这种方法,它将返回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; } 

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

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

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

我不确定2012年原来的问题是什么时候回来的。

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

因此,如果以root用户身份运行InetAddress.getByName(“www.google.com”)。isReacheable(5000),它应该返回true。

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

InetAddress.getByName和ping一样可靠,但是您需要在进程上拥有适当的权限才能使其正常运行。

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

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

  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(数据包)的次数,如果你有繁忙的网络或系统选择biger nping号码。
wping是ip从ipong等待的时间,你可以设置它2000ms
为了使用这个方法,你可以这样写:

 isReachable(5, 2000, "192.168.7.93"); 

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