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)
но я не уверен, что для этого также потребуется тайм-аут.