首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android 獲取本機 IP 卻拿到 10.0.2.15?真相其實是模擬器網路架構

     編輯:程式設計綜合問答

許多 Android 開發者在真機或模擬器上呼叫 NetworkInterface.getNetworkInterfaces() 遍歷 IP 時,發現取得的永遠是 10.0.2.15,但系統設定裡顯示的卻是 10.88.x.x 或 WiFi 下的 10.225.x.x。這到底發生了什麼事?

問題重現:典型取 IP 程式碼

public String getLocalIpAddress() {
    try {
        for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
            NetworkInterface intf = en.nextElement();
            for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
                InetAddress inetAddress = enumIpAddr.nextElement();
                if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress()) {
                    return inetAddress.getHostAddress();
                }
            }
        }
    } catch (SocketException ex) {
        Log.e("WifiPreference IpAddress", ex.toString());
    }
    return null;
}

核心原因:模擬器的 NAT 網路架構

10.0.2.15 是 Android 模擬器預設給客體(Guest OS)的私有 IP。模擬器啟動時會建立一個虛擬網路:

  • 宿主機(Host)對模擬器可見 IP:10.0.2.2
  • 模擬器自身對外連線時,經由 QEMU 內建 NAT 轉發,來源 IP 固定為 10.0.2.15

因此 NetworkInterface 枚舉到的第一張非回環、非 Link-Local 介面通常是 eth0(虛擬乙太網卡),其 IP 正是 10.0.2.15。

真機為何也可能出現類似情況?

  1. 介面遍歷順序不固定:getNetworkInterfaces() 回傳順序由底層驅動決定,可能先拿到 rmnet_data0(行動數據)或 wlan0(WiFi),甚至 lo(回環)的下一個。
  2. VPN / 熱點 / Docker 等虛擬介面:會插入額外介面,導致第一個符合條件的 IP 非預期值。

正確做法:指定介面或過濾邏輯

方案 A:只取 WiFi 介面(最常見需求)

public String getWifiIpv4() {
    try {
        for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
            NetworkInterface intf = en.nextElement();
            if (!intf.getName().startsWith("wlan")) continue; // 只看 WiFi
            for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
                InetAddress inetAddress = enumIpAddr.nextElement();
                if (inetAddress instanceof Inet4Address && !inetAddress.isLoopbackAddress()) {
                    return inetAddress.getHostAddress();
                }
            }
        }
    } catch (SocketException e) {
        e.printStackTrace();
    }
    return null;
}

方案 B:優先取得有網路連線的介面

ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network activeNet = cm.getActiveNetwork();
if (activeNet != null) {
    NetworkCapabilities caps = cm.getNetworkCapabilities(activeNet);
    if (caps != null && caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
        // 繫結到該 Network 再取 IP,確保拿到正確介面
    }
}

權限別忘了

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- Android 10+ 需要 -->

總結

10.0.2.15 不是 Bug,是模擬器 NAT 架構的必然產物。真機上則是介面遍歷順序導致。解決關鍵在於明確指定想要的介面類型(wlan/rmnet),而非盲目取第一個符合條件的 IP。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved