[java] How to test if a remote system is reachable

Programatically using ICMP Ping is a great way to establish that a server is up and running. Previously you couldn’t do ICMP ping (what ping command does in Linux/Unix & Windows) in java without using JNI or exec calls. Here is a simple and reliable method to do ICMP pings in Java without using JNI or NIO.


String host = "172.16.0.2"
int timeOut = 3000; // I recommend 3 seconds at least
boolean status = InetAddress.getByName(host).isReachable(timeOut)

status is true if the machine is reachable by ping; false otherwise. Best effort is made to try to reach the host, but firewalls and server configuration may block requests resulting in a unreachable status while some specific ports may be accessible. A typical implementation will use ICMP ECHO REQUESTs if the privilege can be obtained, otherwise it will try to establish a TCP connection on port 7 (Echo) of the destination host.

In Linux/Unix you may have to suid the java executable to get ICMP Ping working, ECHO REQUESTs will be fine even without suid. However on Windows you can get ICMP Ping without any issues whatsoever.


The check method can be rewritten as follows (Java 7 and later):

public static boolean hostAvailabilityCheck() { 
    try (Socket s = new Socket(SERVER_ADDRESS, TCP_SERVER_PORT)) {
        return true;
    } catch (IOException ex) {
        /* ignore */
    }
    return false;
}

In addition to simplifying the exception handling, this eliminates a pesky Socket leak. (If you are concerned with the time taken to do this check, then set a connection timeout before attempting to connect: see Setting a timeout for socket operations)

But the problems with this approach are many-fold:

  • It only tests that something is listening for connections. If your service is behind a proxy … or is managed by something like the inetd service … then the accepted connections don’t mean your service is actually working.
  • This is going to cause your service to “see” connections that close down without sending a request. So you’d better code your service to deal with this “gracefully”.
  • Doing this repeatedly adds to network and server load.
  • If you set a short timeout because you don’t want the test to “freeze”, then you risk setting it too short and judging the host to be down when it isn’t.

After server is started I want to stop checking until the server changes status

That is next to impossible. The reason is that you won’t be able to tell whether the server has “changed status” without checking. Or at least, you won’t be able to do this without implementing an elaborate status notification service where the server calls the client to tell it is changing status. (And if “change status” includes “die” or “lost network connection”, then you won’t be able to make that notification reliable … if at all.)


Use the Socket() constructor, and connect(SocketAddress endpoint, int timeout) methodinstead.

In your case it would look something like:

Socket socket = new Socket();
socket.connect(new InetSocketAddress(ipAddress, port), 1000);

Quoting from the documentation

connect

public void connect(SocketAddress endpoint, int timeout) throws IOException

Connects this socket to the server with a specified timeout value. A timeout of zero is interpreted as an infinite timeout. The connection will then block until established or an error occurs.

Parameters:

endpoint – the SocketAddress
timeout – the timeout value to be used in milliseconds.

Throws:

IOException – if an error occurs during the connection
SocketTimeoutException – if timeout expires before connecting
IllegalBlockingModeException – if this socket has an associated channel, and the channel is in non-blocking mode
IllegalArgumentException – if endpoint is null or is a SocketAddress subclass not supported by this socket

Since: 1.4

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *