1. 程式人生 > >Java 網路程式設計(1):使用 NetworkInterface 獲得本機在區域網內的 IP 地址

Java 網路程式設計(1):使用 NetworkInterface 獲得本機在區域網內的 IP 地址

原文地址:https://segmentfault.com/a/1190000007462741

1、問題提出

在使用 Java 開發網路程式時,有時候我們需要知道本機在區域網中的 IP 地址。很常見的一種做法是呼叫本地命令(比如 Windows 上的 ipconfig 命令和 Linux 上的 ifconfig 命令),接著解析本地命令的輸出,最後得到本機在區域網內的 IP 地址。很明顯,這種做法不夠方便,也不夠 Java。於是引出了 Java 在 JDK1.4 的時候新增的一個類: NetworkInterface 。

2、尋找方法

顧名思義,NetworkInterface 用於表示一個網路介面,這可以是一個物理的網路介面,也可以是一個虛擬的網路介面,而一個網路介面通常由一個 IP 地址來表示。既然 NetworkInterface 用來表示一個網路介面,那麼如果可以獲得當前機器所有的網路介面(包括物理的和虛擬的),然後篩選出表示區域網的那個網路介面,那就可以得到機器在區域網內的 IP 地址。

檢視 NetworkInterface 類的所有方法,發現如下兩個方法:

public static Enumeration getNetworkInterfaces()
通過 API 文件可知,使用 getNetworkInterfaces 方法即可得到當前機器上所有的網路介面。

public Enumeration getInetAddresses()
通過 API 文件可知,getInetAddresses 方法返回繫結到該網絡卡的所有的 IP 地址。(雖然一個網路介面確實可以繫結多個 IP 地址,然而通常情況下,一個網路介面都是隻對應一個 IP 地址)

3、實踐

OK,現在讓電腦連線上 WiFi,來實踐下 NetworkInterface 的功能。

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

public class NetworkInterfaceTest {

    public static void main(String[] args) throws Exception {
        // 獲得本機的所有網路介面
        Enumeration<NetworkInterface> nifs = NetworkInterface.
getNetworkInterfaces(); while (nifs.hasMoreElements()) { NetworkInterface nif = nifs.nextElement(); // 獲得與該網路介面繫結的 IP 地址,一般只有一個 Enumeration<InetAddress> addresses = nif.getInetAddresses(); while (addresses.hasMoreElements()) { InetAddress addr = addresses.nextElement(); if (addr instanceof Inet4Address) { // 只關心 IPv4 地址 System.out.println("網絡卡介面名稱:" + nif.getName()); System.out.println("網絡卡介面地址:" + addr.getHostAddress()); System.out.println(); } } } } }

在我機器(Windows10)上執行結果:

執行結果

對比使用 ipconfig 命令得到的結果:

ipconfig的結果

可以發現

網絡卡介面名稱:wlan1
網絡卡介面地址:192.168.3.5
即為機器在區域網內的 IP 地址 —— Windows 平臺上區域網的網路介面以“wlan”開頭。(lo 為本地迴環地址,eth0 和 eth4 為 VMware 建立的虛擬地址)

於是我們可以寫出一個簡單的在 Windows 機器上獲得區域網 IP 地址的方法:

public InetAddress getLANAddressOnWindows() {
    try {
        Enumeration<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces();
        while (nifs.hasMoreElements()) {
            NetworkInterface nif = nifs.nextElement();

            if (nif.getName().startsWith("wlan")) {
                Enumeration<InetAddress> addresses = nif.getInetAddresses();

                while (addresses.hasMoreElements()) {

                    InetAddress addr = addresses.nextElement();
                    if (addr.getAddress().length == 4) { // 速度快於 instanceof
                        return addr;
                    }
                }
            }
        }
    } catch (SocketException ex) {
        ex.printStackTrace(System.err);
    }
    return null;
}

(該方法沒有考慮 Windows 平臺上有多個網路介面的名稱以 “wlan” 開頭的情況,比如你的機器連線了 WiFi,然後又使用該機器作為熱點 —— 不過很容易對二者進行區分,請有興趣的讀者自己實踐)

在 JDK1.6 時 NetworkInterface 還添加了一個新的方法:

public List getInterfaceAddresses()
getInterfaceAddresses 方法的作用與 getInetAddresses 方法類似,但是返回的是一個繫結到該網路介面的所有 InterfaceAddress 的集合。InterfaceAddress 也是 JDK1.6 之後新增的類,相比於 InetAddress 的區別在於它除了具有一個 IP 地址(InetAddress),還包括了該地址對應的廣播地址和掩碼長度。

4、總結
當然,使用 NetworkInterface 類來獲取機器在區域網內的 IP 地址還是有一定的平臺相關性,但是相比於使用本地命令的方式來說,會更加方便和更加的 Java 。
PS:在 Android 平臺上同樣可以使用 NetworkInterface 來實現獲得機器在區域網內 IP 地址的功能。