首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 獲取本機 IP 與 MAC 地址完整實現(含虛擬網卡過濾)

     編輯:Java 相關知識

生產環境常需獲取服務器真實 IP 和 MAC(如註冊服務發現、分布式鎖、審計日誌)。本文提供生產級工具類,自動過濾回環、虛擬、未啟用網卡,優先返回 IPv4 物理網卡地址,並補充作業系統判斷、HTTP 代理設置等常用網絡工具方法。

核心工具類:NetworkUtil


import java.net.*;
import java.util.Enumeration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class NetworkUtil {
    private static final Logger log = LoggerFactory.getLogger(NetworkUtil.class);

    /** 獲取首個有效 IPv4 地址 (過濾回環、虛擬、未啟用網卡) */
    public static String getLocalIpAddress() {
        try {
            Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface ni = interfaces.nextElement();
                // 關鍵過濾條件
                if (ni.isLoopback() || ni.isVirtual() || !ni.isUp()) continue;
                
                Enumeration addresses = ni.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress addr = addresses.nextElement();
                    if (addr instanceof Inet4Address && !addr.isLoopbackAddress()) {
                        return addr.getHostAddress();
                    }
                }
            }
        } catch (SocketException e) {
            log.error("獲取 IP 失敗", e);
        }
        return "";
    }

    /** 獲取對應物理網卡的 MAC 地址 (格式: XX-XX-XX-XX-XX-XX) */
    public static String getMacAddress() {
        try {
            Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface ni = interfaces.nextElement();
                if (ni.isLoopback() || ni.isVirtual() || !ni.isUp()) continue;
                
                byte[] mac = ni.getHardwareAddress();
                if (mac != null && mac.length == 6) {
                    StringBuilder sb = new StringBuilder(17);
                    for (int i = 0; i < mac.length; i++) {
                        sb.append(String.format("%02X", mac[i]));
                        if (i < mac.length - 1) sb.append('-');
                    }
                    return sb.toString();
                }
            }
        } catch (SocketException e) {
            log.error("獲取 MAC 失敗", e);
        }
        return "";
    }

    /** 綁定 IP 與 MAC(確保來自同一張網卡) */
    public static Pair getIpAndMac() {
        try {
            Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                NetworkInterface ni = interfaces.nextElement();
                if (ni.isLoopback() || ni.isVirtual() || !ni.isUp()) continue;
                
                byte[] mac = ni.getHardwareAddress();
                if (mac == null || mac.length != 6) continue;
                
                Enumeration addresses = ni.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress addr = addresses.nextElement();
                    if (addr instanceof Inet4Address && !addr.isLoopbackAddress()) {
                        StringBuilder sb = new StringBuilder(17);
                        for (int i = 0; i < mac.length; i++) {
                            sb.append(String.format("%02X", mac[i]));
                            if (i < mac.length - 1) sb.append('-');
                        }
                        return new Pair<>(addr.getHostAddress(), sb.toString());
                    }
                }
            }
        } catch (SocketException e) {
            log.error("獲取 IP+MAC 失敗", e);
        }
        return new Pair<>("", "");
    }
}

關鍵過濾邏輯解析

過濾條件方法作用
回環網卡ni.isLoopback()排除 127.0.0.1 / ::1 等本地回環介面
虛擬網卡ni.isVirtual()排除 Docker(veth)、VPN(tun)、Hyper-V 等虛擬介面
未啟用!ni.isUp()排除禁用、未連接、拔掉網線的介面
IPv4 優先addr instanceof Inet4Address業務多用 IPv4,IPv6 可作備選
非回環地址!addr.isLoopbackAddress()雙重保險,排除 127.x.x.x

補充:常用網絡工具方法

1. 判斷作業系統類型


public enum OsType { WINDOWS, MAC, LINUX, OTHER }

public static OsType getOsType() {
    String os = System.getProperty("os.name").toLowerCase();
    if (os.contains("win")) return OsType.WINDOWS;
    if (os.contains("mac") || os.contains("darwin")) return OsType.MAC;
    if (os.contains("nix") || os.contains("nux") || os.contains("aix")) return OsType.LINUX;
    return OsType.OTHER;
}

2. 設置 JVM 級 HTTP/HTTPS 代理 (全局生效)


public static void setHttpProxy(String host, int port, String nonProxyHosts) {
    System.setProperty("http.proxyHost", host);
    System.setProperty("http.proxyPort", String.valueOf(port));
    System.setProperty("https.proxyHost", host);
    System.setProperty("https.proxyPort", String.valueOf(port));
    if (nonProxyHosts != null) {
        System.setProperty("http.nonProxyHosts", nonProxyHosts);
        System.setProperty("https.nonProxyHosts", nonProxyHosts);
    }
}

public static void clearHttpProxy() {
    System.clearProperty("http.proxyHost");
    System.clearProperty("http.proxyPort");
    System.clearProperty("https.proxyHost");
    System.clearProperty("https.proxyPort");
    System.clearProperty("http.nonProxyHosts");
    System.clearProperty("https.nonProxyHosts");
}

注意:系統屬性代理對 `HttpURLConnection`、`HttpClient` (舊版)、`WebService` 等生效,**不影響** OkHttp、Netty 等自帶連接池的客戶端,需單獨配置。

3. 獲取所有網卡詳細信息 (診斷用)


public static void printAllInterfaces() {
    try {
        Enumeration nis = NetworkInterface.getNetworkInterfaces();
        while (nis.hasMoreElements()) {
            NetworkInterface ni = nis.nextElement();
            System.out.printf("Name: %s, Display: %s, Up: %b, Loopback: %b, Virtual: %b, MAC: %s%n",
                ni.getName(), ni.getDisplayName(), ni.isUp(), ni.isLoopback(), ni.isVirtual(),
                formatMac(ni.getHardwareAddress()));
            Enumeration addrs = ni.getInetAddresses();
            while (addrs.hasMoreElements()) {
                InetAddress addr = addrs.nextElement();
                System.out.printf("  IP: %s (%s)%n", addr.getHostAddress(), 
                    addr instanceof Inet4Address ? "IPv4" : "IPv6");
            }
        }
    } catch (SocketException e) { log.error("列舉網卡失敗", e); }
}

容器化環境特別說明

  • Docker 容器:`eth0` 通常是容器內部 IP (如 172.17.0.x),宿主機 IP 需通過 `host.docker.internal` (Docker Desktop) 或元數據服務獲取。
  • Kubernetes Pod:Pod IP 為內部 IP,對外暴露需 Service/Ingress。獲取節點 IP 可用 `Downward API` 注入 `status.hostIP`。
  • 雲服務器:阿里雲/騰訊雲/EC2 內網 IP 為私有 IP,公網 IP 需查詢元數據服務 (如 `https://100.100.100.200/latest/meta-data/public-ipv4`)。

常見問題排查

現象可能原因排查步驟
返回空字串無符合條件的網卡調用 `printAllInterfaces()` 查看實際網卡狀態
獲取到 Docker 虛擬 IP未過濾 isVirtual()確認 JDK 版本支援 isVirtual() (Java 8u151+)
MAC 為 null某些虛擬/隧道介面無 MAC增加 `mac != null && mac.length == 6` 校驗
Windows 多網卡順序不定Enumeration 順序不保證按介面名稱排序 (如優先 Ethernet、Wi-Fi)

依賴建議

  • 無第三方依賴,純 JDK (`java.net.NetworkInterface`) 實現。
  • 日誌使用 SLF4J,可換 Logback/Log4j2。
  • Java 8+ 即可運行,`isVirtual()` 需 8u151+。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved