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


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

为什么要isReachable退货false?我可以ping通IP。



1
这是相似的。但我找不到解决此问题的任何线索。因此,我在这里提出了建议。感谢您的提醒!
jiafu 2012年

2
我会尝试增加超时时间。
jayunit100

这是一个很好的问题,投票不足。我发现的唯一类似问题被标记为clojure问题,答案没有定论。
jayunit100

3
有人可以告诉我isReachable()到底是做什么的吗?它甚至在本地主机上也返回我为假...
Seth Keno 2014年

Answers:


73

在许多情况下,“ isReachable”方法对我而言并不值得使用。您可以滚动到底部以查看我的替代方法,该方法可以简单地测试您是否在线并且能够解析外部主机(例如google.com)...这似乎通常可以在* NIX机器上使用。

问题

关于此有很多of不休:

第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)此解决方案不是生产质量。这有点hack。如果google关闭,或者您的互联网暂时变慢,或者即使您的权限/系统设置有些有趣,是否可能返回假阴性(即即使输入地址可访问也可能失败)。2)isReachable失败是一个突出的问题。再说一次-由于JVM尝试访问主机的方式,有许多在线资源表明在撰写本文时尚无“完美”的方法可以做到-我想这是一个固有的平台特定任务,尽管很简单尚未被JVM充分抽象。


@ jayunit100两种方法都不起作用,isReachable我失败了,使用ping却不允许icmp吗?您知道现在如何处理吗?
Yuvi 2013年

6
@Yuvi如果使用Windows,则标志会有所不同。您需要-n而不是-c。
James T Snell 2013年

waitFor()需要10秒钟才能返回。Java 7中有没有办法提及超时?
Jaydev '17

@Jaydev,也有一个重载的选项:public boolean waitFor(long timeout, TimeUnit unit)在java.lang.Process(@since 1.8)中
不可分割

从2020年1月起,我可以毫无问题地运行该问题的示例,它报告一个IPv4地址和一个IPv6地址的“已连接”。该错误在Java 5.0 b22中也已修复。isReachable如今也许更可靠。
Lii

54

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

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
这是一个出色的平台独立解决方案,谢谢!
ivandov '16

1
我很高兴自己到这里结束,这是
Sourabh的

所以,只是为了确保我完全理解:只要没有例外,地址是可以到达的?
Timmiej93

1
这与InetAddress.isReachable()通过端口7进行的操作相同,不同之处在于端口7 IOExceptions对于可及性方面的各种可能含义更为智能。
罗恩侯爵,

1
是的@EJP我认为,如果InetAddress.isReachable()在标准库中重载port参数,那就太好了。我想知道为什么不包括在内?
苏拉卜·巴特

7

如果仅想使用此方法检查它是否已连接到Internet,则在连接了Internet时返回true;如果您使用尝试通过程序连接的站点地址,则返回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;
    }

2
如果服务器没有Web服务器,则无用,这根本不是问题中指定的条件。
Fran Marzoa 2014年

3

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

而且,如果您问为什么从bash进行ping不起作用,实际上也确实需要。这样做ls -l / bin / ping。

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


3

我不确定在2012年提出原始问题时的状态。

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

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

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

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


0

我建议测试互联网连接的唯一可靠方法是实际连接并下载文件,或者通过exec()解析OS Ping调用的输出。您不能依靠退出代码来执行ping操作,而isReachable()很糟糕。

您不能依赖ping退出代码,因为如果ping命令正确执行,它将返回0。不幸的是,如果ping无法到达目标主机但从您的家庭ADSL路由器获得“目标主机不可达”,它将正确执行。这是一种成功的答复,因此退出代码=0。尽管必须在Windows系统上进行补充。未选中* 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是尝试ping ip(数据包)的次数,如果网络或系统繁忙,请选择更大的nping号码。
wping是从ip等待pong的时间,您可以将其设置为2000ms
以使用此方法,您可以 这样编写:

isReachable(5, 2000, "192.168.7.93");

潜在的命令注入,请确保在运行此命令之前验证字符串输入
间谍

还有“一般故障”错误消息。这也看起来像特定于Windows的窗口。我很确定这些错误消息都以不同的语言进行了本地化,因此不是超级可移植的。
间谍

这是用于Windows系统。
阿明·莫克里

是的,我以前在窗户上看过
间谍

0

或使用这种方式:

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 是不稳定的,有时对于我们可以ping的地址返回无法访问的地址。

我尝试了以下方法:

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

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


-1

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


您不需要特权即可连接到低范围的端口。
罗恩侯爵,2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.