Java Быстрая проверка сетевого подключения

Моя проблема довольно проста. Моя программа требует немедленного уведомления, если сетевое соединение потеряно. Я использую Java 5, поэтому я не могу использовать очень удобные функции NetworkInterface.

В настоящее время у меня есть два разных метода проверки сетевого подключения:
(try..catches удален)

Первый метод:

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;

Способ 2:

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

Однако оба этих метода блокируются до тех пор, пока не будет достигнут тайм-аут, прежде чем возвращать значение false. Мне нужен метод, который будет немедленно возвращаться, но совместим с Java 5.

Спасибо!

EDIT: Я забыл упомянуть, что моя программа зависит от IP-адресов, а не от имен DNS. Поэтому проверка ошибки при разрешении хоста отсутствует...

2nd EDIT:

Выясните окончательное решение, используя 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;
                }
            }
        }

Ответ 1

От JGuru

Начиная с Java 5, существует метод isReachable() в Класс InetAddress. Вы можете указать либо тайм-аут, либо Использовать NetworkInterface. Для получения дополнительной информации об основных Протокол сообщений управления через Интернет (ICMP), используемый ping, см. RFC 792 (http://www.faqs.org/rfcs/rfc792.html).

Использование 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);
  }

Если вы хотите избежать блокировки, используйте Java NIO (Non-blocking IO) в пакете java.nio

String host = ...; 
InetSocketAddress socketAddress = new InetSocketAddress(host, 80); 
channel = SocketChannel.open(); 
channel.configureBlocking(false); 
channel.connect(socketAddress);

Ответ 2

Моя программа требует немедленного уведомления, если сетевое соединение потеряны.

Не повезло. Вы не можете получить немедленное уведомление с помощью TCP/IP. Он заполнен буферизацией и повторениями и тайм-аутами, поэтому он ничего не делает сразу, а TCP по дизайну не имеет ничего, что соответствует "гуру", ни API. Единственный способ обнаружить потерянное соединение - попытаться выполнить ввод/вывод по нему.

Я использую Java 5, поэтому я не могу использовать очень удобные функции NetworkInterface.

Они тоже вам не помогут. Все, что они могут сказать вам, это то, что NIC вверх или вниз, ничего о состоянии вашей связности с более широким миром.

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;

Это будет таймаут с отказом DNS, если вы в автономном режиме.

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

То же самое. Однако, даже если это не так, socket.isConnected() всегда будет возвращать true. Эти API, такие как isConnected(), isBound(), isClosed(), только сообщают вам, что вы сделали с сокетом. Они ничего не говорят о состоянии связи. Они не могут по причине, которую я дал выше.

И вы забыли закрыть сокет в случае исключения, так что у вас есть утечка ресурсов.

Мне нужен метод, который немедленно вернется.

Невозможно по указанным причинам. Вам нужно переделать идею о том, что эта функция не существует.

Ответ 3

Вам нужно сначала создать interface, называемый NetworkListener, например

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

Затем создайте класс и вызовите его NetworkStatusThread, например

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

 }

Затем в вашем классе, который создает экземпляр Thread, выполните следующее:

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

Кроме того, в этом классе вам нужно implement NetworkListener, чтобы получить обратные вызовы.

В вашем методе run() выше вы можете реализовать код @Ali, но передайте мой статус:

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

Ответ 4

Вы пытались решить проблему DNS?

Вы можете попробовать:

public static InetAddress[] getAllByName(String host)

но я не уверен, что для этого также потребуется тайм-аут.