2011-08-09 127 views
10

我的問題相當簡單。如果網絡連接丟失,我的程序需要立即通知。我使用的是Java 5,因此我無法使用NetworkInterface的非常方便的功能。Java快速檢查網絡連接

目前我有檢查的網絡連接的兩種不同的方法:
(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兼容。

謝謝!

編輯: 我忘了提及我的程序依賴於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; 
       } 
      } 
     } 
+0

我對Java不太熟悉,但我認爲方法2中的'http://'太多了。 – glglgl

+0

您可以使用Java 5.0運行可以使用NetworkInterface的Java 6或7應用程序。;) –

+0

好像你需要一個回調方法來在網絡狀態發生變化時通知你。 – 2011-08-09 16:10:43

回答

10

從JGuru

與開始在Java 5中, InetAddress類中有isReachable()方法。您可以指定超時或要使用的NetworkInterface。有關Ping使用的基本 Internet控制消息協議(ICMP)的更多信息,請參閱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(非阻塞IO)

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

不幸的是,這個方法仍然會阻塞,直到到達timout。更糟糕的是,它會阻塞陣列中的每個InetAddress。不過謝謝。 – BenCole

+0

嗯...你需要的是java.nio ...它的名字是NON-BLOCKING-IO 'String host = ...;InetSocketAddress socketAddress = new InetSocketAddress(host,80); channel = SocketChannel.open(); channel.configureBlocking(false); channel.connect(socketAddress);' – Ali

+0

這個工作,但只有當主機不是IP地址。任何方式讓它與IP一起工作呢? – BenCole

0

你發出一個嘗試DNS解析?

你可以嘗試使用:

public static InetAddress[] getAllByName(String host) 

,但我不確定這是否會要求超時太..

+0

這是通過拋出一個UnknownHostException,但只有當主機不是IP地址。 – BenCole

+0

沒看過你有這個要求,對不起 – Jack

2

您需要先創建一個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(); 

另外,在該類中,您需要implementNetworkListener,才能獲得回調。

在你上面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

謝謝!我以前一直在使用Timer和TimerTask的匿名子類,但我會給這個鏡頭。 – BenCole

+0

只適用於互聯網連接的連接。問題在於網絡連接的改變,而不是連接到谷歌 – spy

3

我的程序,需立即告知如果網絡連接是 丟失。

運氣不好。您無法使用TCP/IP立即收到通知。它充滿了緩衝,重試和超時,因此它不會立即執行任何事情,並且TCP通過設計沒有與'撥號音'相對應的任何內容,也沒有任何API。檢測丟失連接的唯一方法是嘗試對其執行I/O操作。

我使用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(),只會告訴你對套接字做了什麼。他們不會告訴你有關連接狀態的任何信息。由於我上面給出的原因,他們不能。

而且在發生異常的情況下忘記關閉套接字,所以您有資源泄漏。

我需要一個立即返回的方法。

不可能的原因。你需要重新設計這個功能不存在的認識。

+0

實際上,我能夠使用NetworkInterface的功能(我認爲)弄清楚了這一點。檢查上面的第二個編輯。另外,我不知道你是否看到了,但是在調用'isConnected()'後立即調用'socket.close()'。 – BenCole

+0

如果發生異常,忘記關閉套接字。 – EJP