11

My issue is fairly straightforward. My program requires immediate notification if a network connection is lost. I'm using Java 5, so I'm unable to use the very handy features of NetworkInterface.

Currently I have two different methods of checking for a network connection:
(try..catches removed)

Method One:

URL url = new URL("http://www.google.com");
HttpURLConnection urlConnect = (HttpURLConnection) url.openConnection();
// trying to retrieve data from the source. If offline, this line will fail:
Object objData = urlConnect.getContent();
return true;

Method 2:

Socket socket = new Socket("www.google.com", 80);
netAccess = socket.isConnected();
socket.close();
return netAccess;

However, both of these methods block until a Timeout is reached before returning false. I need a method that will return immediately, but is compatible with Java 5.

Thanks!

EDIT: I forgot to mention that my program is reliant on IP addresses, not DNS names. So checking for an error when resolving a host is out...

2nd EDIT:

Figured out a final solution using NetworkInterface:

Enumeration<NetworkInterface> eni = NetworkInterface.getNetworkInterfaces();
        while(eni.hasMoreElements()) {
            Enumeration<InetAddress> eia = eni.nextElement().getInetAddresses();
            while(eia.hasMoreElements()) {
                InetAddress ia = eia.nextElement();
                if (!ia.isAnyLocalAddress() && !ia.isLoopbackAddress() && !ia.isSiteLocalAddress()) {
                    if (!ia.getHostName().equals(ia.getHostAddress()))
                        return true;
                }
            }
        }
BenCole
  • 2,092
  • 3
  • 17
  • 26
  • I'm not quite familiar with Java, but I think the `http://` in method 2 is too much. – glglgl Aug 09 '11 at 16:10
  • You can use Java 5.0 to run a Java 6 or 7 application which can use NetworkInterface. ;) – Peter Lawrey Aug 09 '11 at 16:10
  • seems like you need a callback method to notify you when something changes in the network state. –  Aug 09 '11 at 16:10
  • oops. That's not actually in production code...I'll remove it. – BenCole Aug 09 '11 at 16:10
  • @CodeMonkey, that's what I'm going for...I spawn I separate thread just for this task. – BenCole Aug 09 '11 at 16:12
  • 2
    I'm a bit confused by what you are trying to do. Whichever way you check if the connection is still available, you need to communicate over the network and data does take some time to travel on a network. I don't see how anyone can "immediatly" know if a connection is still active. You do need a timeout. – toto2 Aug 09 '11 at 16:48

4 Answers4

10

From JGuru

Starting with Java 5, there is an isReachable() method in the InetAddress class. You can specify either a timeout or the NetworkInterface to use. For more information on the underlying Internet Control Message Protocol (ICMP) used by ping, see RFC 792 (http://www.faqs.org/rfcs/rfc792.html).

Usage from Java2s

  int timeout = 2000;
  InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
  for (InetAddress address : addresses) {
    if (address.isReachable(timeout))
      System.out.printf("%s is reachable%n", address);
    else
      System.out.printf("%s could not be contacted%n", address);
  }

If you want to avoid blocking use Java NIO (Non-blocking IO) in the java.nio package

String host = ...; 
InetSocketAddress socketAddress = new InetSocketAddress(host, 80); 
channel = SocketChannel.open(); 
channel.configureBlocking(false); 
channel.connect(socketAddress);
Ali
  • 12,354
  • 9
  • 54
  • 83
  • Unfortunately this method will still block until the timout is reached. Even worse, it will block for each InetAddress in the array. Thanks though. – BenCole Aug 09 '11 at 16:25
  • Hmmm... what you need is java.nio... it by name is NON-BLOCKING-IO `String host = ...; InetSocketAddress socketAddress = new InetSocketAddress(host, 80); channel = SocketChannel.open(); channel.configureBlocking(false); channel.connect(socketAddress);` – Ali Aug 09 '11 at 16:28
  • This works, but only if host is NOT an IP address. Any way to get it to work with IPs also? – BenCole Aug 09 '11 at 16:35
  • I'm not too familiar with NIO, however `InetSocketAddress` has a constructor that takes `InetAddress`, does this help? `InetSocketAddress(InetAddress addr, int port)` – Ali Aug 09 '11 at 16:43
  • InetSocketAddress api basically suggests that it SHOULD work with an IP address.. could something else be a problem? http://download.oracle.com/javase/1.4.2/docs/api/java/net/InetSocketAddress.html – Ali Aug 09 '11 at 16:46
  • I think the issue is more in InetAddress. It takes either a byte array or a string. If the string is an IP, it only checks the form (ie, four complete octets) not the validity. [link]http://download.oracle.com/javase/1.4.2/docs/api/java/net/InetAddress.html#getByAddress(java.lang.String, byte[]) – BenCole Aug 09 '11 at 16:54
  • Why not just use a host name and make an entry in your hosts file? – Ali Aug 09 '11 at 16:59
  • That's a better idea than anything I'd come up with. I'll use that for server-status checking, and just try to resolve hostnames for general connection checking. – BenCole Aug 09 '11 at 17:08
  • this code doesnt works... i tried it with my internet connected but still it doesnt works – Azuu Apr 13 '13 at 08:41
  • Only works for internet connected connections. The question for was a change in network connections, not connectivity to google – spy Jan 02 '16 at 19:02
4

You need to first create an interface called NetworkListener, for example

public interface NetworkListener {
    public void sendNetworkStatus(String status);
}

Next, create a class and call it NetworkStatusThread, for example

public class NetworkStatusThread implements Runnable {
    List listenerList = new Vector();

    @SuppressWarnings("unchecked")
    public synchronized void addNetworkListener(NetworkListener nl) {
        listenerList.add(nl);
    }

    public synchronized void removeNetworkListener(NetworkListener nl) {
        listenerList.remove(nl);
    }


    private synchronized void sendNetworkStatus(String status) {
        // send it to subscribers
        @SuppressWarnings("rawtypes")
        ListIterator iterator = listenerList.listIterator();
        while (iterator.hasNext()) {
            NetworkListener rl = (NetworkListener)iterator.next();
            rl.sendNetworkStatus(status);
        }
    }

    public void run() {
        while (true) {
        System.out.println("Getting resource status");
        try {
             Thread.sleep(2000);
             System.out.println("Sending resource status to registered listeners");
             this.sendResourceStatus("OK");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

 }

Then in your class that instantiates the Thread, do this:

NetworkStatusThread netStatus = new NetworkStatusThread();
netStatus.addNetworkListener(this);
Thread t = new Thread(netStatus);
t.Start();

Also, in that class, you need to implement the NetworkListener, in order to get the callbacks.

In your run() method above, you can implement the code by @Ali, but pass my status:

  int timeout = 2000;
  InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
  for (InetAddress address : addresses) {
    if (address.isReachable(timeout))
       this.sendResourceStatus("OK");
    else
       this.sendResourceStatus("BAD");
  }
  • Thanks! I'd previously been using Timer and an anonymous subclass of TimerTask, but I'll give this a shot. – BenCole Aug 09 '11 at 16:44
  • Only works for internet connected connections. The question for was a change in network connection, not connectivity to google – spy Jan 02 '16 at 19:02
3

My program requires immediate notification if a network connection is lost.

Bad luck. You can't get an immediate notification with TCP/IP. It is full of buffering and retries and timeouts, so it doesn't do anything immediately, and TCP by design doesn't have anything corresponding to a 'dial tone', nor any API. The only way to detect a lost connection is to try to do I/O over it.

I'm using Java 5, so I'm unable to use the very handy features of NetworkInterface.

They won't help you either. All they can tell you is whether an NIC is up or down, nothing about the state of your connectedness to the wider world.

URL url = new URL("http://www.google.com");
HttpURLConnection urlConnect = (HttpURLConnection) url.openConnection();
// trying to retrieve data from the source. If offline, this line will fail:
Object objData = urlConnect.getContent();
return true;

That will timeout with a DNS failure if you're offline.

Socket socket = new Socket("www.google.com", 80);
netAccess = socket.isConnected();
socket.close();
return netAccess;

Ditto. However even if it didn't, socket.isConnected() would always return true. Those APIs like isConnected(), isBound(), isClosed(), only tell you what you have done to the socket. They don't tell you anything about the state of the connection. They can't, for the reason I gave above.

And you forgot to close the socket in the case of an exception, so you have a resource leak.

I need a method that will return immediately.

Impossible for the reasons given. You need to redesign around the realization that this function doesn't exist.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Actually, I was able to figure this out using the functionality of NetworkInterface (I think). Check the 2nd Edit above. Also, I don't know if you saw, but I call `socket.close()` right after calling `isConnected()`.... – BenCole Aug 10 '11 at 13:05
  • You forget to close the socket in the case of an exception. – user207421 Nov 12 '17 at 22:55
0

Did you try by issuing a DNS resolve?

You can try with:

public static InetAddress[] getAllByName(String host)

but I'm unsure if this will require the timeout too..

Jack
  • 131,802
  • 30
  • 241
  • 343