108
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.

dwb
  • 2,136
  • 13
  • 27
jiafu
  • 6,338
  • 12
  • 49
  • 73
  • Possible duplicate: http://stackoverflow.com/questions/4779367/problem-with-isreachable-in-inetaddress-class – assylias Mar 29 '12 at 09:32
  • 1
    it is similar. but I can't found any clue to solve the problem.So I reraised it here. Thank for your reminder! – jiafu Mar 29 '12 at 12:18
  • 2
    I would try increasing the timeout. – jayunit100 Apr 13 '12 at 17:01
  • this is a very good question, theres not enough upvotes. The only similar question i found was tagged as a clojure question and the answer was inconclusive. – jayunit100 Apr 13 '12 at 17:07
  • 6
    can someone tell me what exactly isReachable() does? it returns me false even on localhost... – Seth Keno Apr 21 '14 at 22:10

12 Answers12

75

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.

The issue

There is alot of chatter about this :

Part 1 : A reproducible example of the problem

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).

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

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.

Community
  • 1
  • 1
jayunit100
  • 17,388
  • 22
  • 92
  • 167
  • @jayunit100 for neither of approach is working, of `isReachable` I am getting failed and using ping I am getting icmp not permitted ? Do you know how to deal with it now ? – Yuvi Jan 07 '13 at 08:58
  • 6
    @Yuvi If you're using Windows, the flags differ. Instead of -c you want -n. – James T Snell Oct 21 '13 at 22:31
  • waitFor() takes 10 seconds to return. Is there a way to mention timeout in Java 7? – Jaydev Jan 20 '17 at 06:41
  • @Jaydev, there is an overloaded option too: `public boolean waitFor(long timeout, TimeUnit unit)` in java.lang.Process (@since 1.8) – indivisible Feb 20 '17 at 11:24
  • As of 2020-01 I can run the example of the problem without any problems, it reports "Connected" for one IPv4 and one IPv6 address. The [bug](https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4921816) is also fixed in Java 5.0 b22. Maybe `isReachable` is more reliable now days. – Lii Jan 23 '20 at 15:10
  • This is not an answer to the question. – Paula Livingstone Aug 18 '20 at 16:21
74

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

Update: Based on a recent comment to this answer, here is a succinct version of the above code:

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;
    }
}
Sourabh Bhat
  • 1,793
  • 16
  • 21
  • 3
    This is a great platform independent solution, thank you! – ivandov Feb 17 '16 at 19:02
  • 1
    I'm happy I ended up here, nice way of thinking Sourabh :) – JustADev Mar 12 '16 at 20:43
  • So, just to make sure I completely understand: As long as there's no exception, the address was reachable? – Timmiej93 Jun 28 '16 at 17:40
  • The `connect()` method throws an `IOException` if it is not able to connect to the port on the other machine. When the specified port on the other machine is open, your machine will be able to connect to it. If it does not, than either the port is closed or the machine is not reachable within the prescribed timeout. Therefore, you can safely assume that the machine is not reachable, provided that you are sure that a particular machine's port has to be open. For example, in case of a webserver running on port 80, the server is of no use if the port 80 is closed. – Sourabh Bhat Jun 30 '16 at 10:40
  • This didn't work for every computer on my network. 1 in particular, I think it's because of antivirus software on it but still the software Advanced IP Scanner was able to detect it with no problem. – Muhammad Ali Nov 12 '16 at 17:59
  • It might be that the port you are trying to connect to, is not open? The IP scanner must be using some other method to scan for IPs, I guess. Assuming that you want to connect to the computer to communicate, it must have some port open; you must try to use that port number. – Sourabh Bhat Nov 12 '16 at 22:52
  • @MuhammadAli You can try this: for(int port = 0; port < 32000; port++) { System.out.printf(isReachable("192.168.0.10", port, 500) ? port + "open\n" : ""); } – Sourabh Bhat Nov 12 '16 at 23:05
  • 1
    This is identical to what `InetAddress.isReachable()` already does, via port 7, except that the latter is more intelligent about what the various possible `IOExceptions` mean in terms of reachability. – user207421 Dec 16 '16 at 04:51
  • 1
    Yes @EJP I think it would be great if `InetAddress.isReachable()` was overloaded to include the port argument, in the standard library. I wonder why it was not included? – Sourabh Bhat Dec 18 '16 at 13:29
  • This is _exactly_ what I was looking for. Thank you! – Collin Alpert Aug 14 '17 at 23:36
  • 1
    Great, thanks! Although I think a single `try` block would be enough, right? Just move the "withResources" part to the outer `try` block and delete the inner one. – tomorrow Mar 02 '22 at 13:07
  • 1
    @tomorrow You are right! I will see if I can update it now. – Sourabh Bhat Mar 03 '22 at 10:38
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.

     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;
    }
CleanX
  • 1,158
  • 3
  • 17
  • 25
4

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:

And if you ask why ping from bash doesn't, actually it does need as well. Do that ls -l /bin/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.

Community
  • 1
  • 1
Zitrax
  • 19,036
  • 20
  • 88
  • 110
4

I am not sure what was the state when the original question was asked back in 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.

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

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

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

Clebert Suconic
  • 5,353
  • 2
  • 22
  • 35
1

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.

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.

cossoft
  • 11
  • 1
0

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.

col
  • 397
  • 3
  • 10
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:

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

Or using this way:

public static boolean exists(final String host)
{
   try
   {
      InetAddress.getByName(host);
      return true;
   }
   catch (final UnknownHostException exception)
   {
      exception.printStackTrace();
      // Handler
   }
   return false;
}
Yousha Aleayoub
  • 4,532
  • 4
  • 53
  • 64
0

InetAddress.isReachable is flappy, and sometimes returns unreachable for addresses which we can ping.

I tried the following:

ping -c 1 <fqdn> and check the exit status.

Works for all the cases i had tried where InetAddress.isReachable doesn't work.

Sandeep Sarkar
  • 399
  • 3
  • 5
0

To Check Internet

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

To check network connectivity

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

        return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
    }
0

Because isReachable is using the TCP protocol(by WireShark) The Ping command is using ICMP protocol,if you want to return true you need to open the 7 port

oFeasl
  • 1
  • * Android implementation attempts ICMP ECHO REQUESTs first, on failure it * will fall back to TCP ECHO REQUESTs. Success on either protocol will * return true. – hyena Aug 08 '21 at 04:30