Java Быстрая проверка сетевого подключения - PullRequest
10 голосов
/ 09 августа 2011

Моя проблема довольно проста.Моя программа требует немедленного уведомления, если сетевое соединение потеряно.Я использую 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;

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

Спасибо!

РЕДАКТИРОВАТЬ: я забыл упомянуть, что моя программа зависит от IP-адресов, а не DNS-имен.Так что проверка на ошибку при разрешении хоста отсутствует ...

2-е РЕДАКТИРОВАНИЕ:

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

Ответы [ 4 ]

10 голосов
/ 09 августа 2011

Из JGuru

Начиная с Java 5, в классе InetAddress есть метод isReachable ().Вы можете указать таймаут или 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 (неблокирующий ввод-вывод) в пакете java.nio

String host = ...; 
InetSocketAddress socketAddress = new InetSocketAddress(host, 80); 
channel = SocketChannel.open(); 
channel.configureBlocking(false); 
channel.connect(socketAddress);
3 голосов
/ 10 августа 2011

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

Неудача. Вы не можете получить немедленное уведомление с 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 (), сообщают только то, что вы сделали с сокетом . Они ничего не сообщают о состоянии соединение. Они не могут, по той причине, которую я привел выше.

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

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

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

2 голосов
/ 09 августа 2011

Сначала необходимо создать 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");
  }
0 голосов
/ 09 августа 2011

Вы пытались выдать разрешение DNS?

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

public static InetAddress[] getAllByName(String host)

, но я не уверен, потребует ли это тоже тайм-аут ..

...