How to ping an IP address

Viewed 281513

I am using this part of code to ping an ip address in java but only pinging localhost is successful and for the other hosts the program says the host is unreachable. I disabled my firewall but still having this problem

public static void main(String[] args) throws UnknownHostException, IOException {
    String ipAddress = "127.0.0.1";
    InetAddress inet = InetAddress.getByName(ipAddress);

    System.out.println("Sending Ping Request to " + ipAddress);
    System.out.println(inet.isReachable(5000) ? "Host is reachable" : "Host is NOT reachable");

    ipAddress = "173.194.32.38";
    inet = InetAddress.getByName(ipAddress);

    System.out.println("Sending Ping Request to " + ipAddress);
    System.out.println(inet.isReachable(5000) ? "Host is reachable" : "Host is NOT reachable");
}

The output is:

Sending Ping Request to 127.0.0.1
Host is reachable
Sending Ping Request to 173.194.32.38
Host is NOT reachable

16 Answers

short recommendation: don't use isReachable(), call the system ping, as proposed in some of the answers above.

long explanation:

  • ping uses the ICMP network protcol. To use ICMP, a 'raw socket' is needed
  • standard users are not allowed by the operating system to use raw sockets
  • the following applies to a fedora 30 linux, windows systems should be similar
  • if java runs as root, isReachable() actually sends ICMP ping requests
  • if java does not run as root, isReachable() tries to connect to TCP port 7, known as the echo port. This service is commonly not used any more, trying to use it might yield improper results
  • any kind of answer to the connection request, also a reject (TCP flag RST) yields a 'true' from isReachable()
  • some firewalls send RST for any port that is not explicitly open. If this happens, you will get isReachable() == true for a host that does not even exist
  • further tries to assign the necessary capabilities to a java process:
  • setcap cap_net_raw+eip java executable (assign the right to use raw sockets)
  • test: getcap java executable -> 'cap_net_raw+eip' (capability is assigned)
  • the running java still sends a TCP request to port 7
  • check of the running java process with getpcaps pid shows that the running java does not have the raw socket capablity. Obviously my setcap has been overridden by some security mechanism
  • as security requirements are increasing, this is likely to become even more restricted, unless s.b. implements an exception especially for ping (but nothing found on the net so far)

Even though this does not rely on ICMP on Windows, this implementation works pretty well with the new Duration API

public static Duration ping(String host) {
    Instant startTime = Instant.now();
    try {
        InetAddress address = InetAddress.getByName(host);
        if (address.isReachable(1000)) {
            return Duration.between(startTime, Instant.now());
        }
    } catch (IOException e) {
        // Host not available, nothing to do here
    }
    return Duration.ofDays(1);
}

I prefer to this way:

   /**
     *
     * @param host
     * @return true means ping success,false means ping fail.
     * @throws IOException
     * @throws InterruptedException
     */
    private static boolean ping(String host) throws IOException, InterruptedException {
        boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win");

        ProcessBuilder processBuilder = new ProcessBuilder("ping", isWindows? "-n" : "-c", "1", host);
        Process proc = processBuilder.start();
        return proc.waitFor(200, TimeUnit.MILLISECONDS);
    }

This way can limit the blocking time to the specific time,such as 200 ms.

It works well in MacOS、Android and Windows, and should used in JDK 1.8.

This idea comes from Mohammad Banisaeid,but I can't comment. (You must have 50 reputation to comment)

I tried a couple of options:

  1. Java InetAddress

InetAddress.getByName(ipAddress), the network on windows started misbehaving after trying a couple of times

  1. Java HttpURLConnection

            URL siteURL = new URL(url);
            connection = (HttpURLConnection) siteURL.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(pingTime);
            connection.connect();
    
            code = connection.getResponseCode();
            if (code == 200) {
                code = 200;
            }.
    

This was reliable but a bit slow

  1. Windows Batch File

I finally settled to creating a batch file on my windows machine with the following contents: ping.exe -n %echoCount% %pingIp% Then I called the .bat file in my java code using

public int pingBat(Network network) {
ProcessBuilder pb = new ProcessBuilder(pingBatLocation);
Map<String, String> env = pb.environment();

env.put(
        "echoCount", noOfPings + "");
env.put(
        "pingIp", pingIp);
File outputFile = new File(outputFileLocation);
File errorFile = new File(errorFileLocation);

pb.redirectOutput(outputFile);

pb.redirectError(errorFile);

Process process;

try {
    process = pb.start();
    process.waitFor();
    String finalOutput = printFile(outputFile);
    if (finalOutput != null && finalOutput.toLowerCase().contains("reply from")) {
        return 200;
    } else {
        return 202;
    }
} catch (IOException e) {
    log.debug(e.getMessage());
    return 203;
} catch (InterruptedException e) {
    log.debug(e.getMessage());
    return 204;
}

}

This proved to be the fastest and most reliable way

Related