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

Java 獲取伺服器 MAC 地址:NetworkInterface 跨平台完整實作

     編輯:Java 相關知識

獲取伺服器 MAC 地址是軟體授權、節點識別、網路診斷的常見需求。傳統做法呼叫系統指令(ipconfig/ifconfig)再解析輸出,不僅平台相依、效能差,還需處理多語系輸出。JDK 1.4+ 引入 java.net.NetworkInterface,1.6 大幅增強功能,提供純 Java 跨平台解決方案。本文提供生產級工具類,含格式化、過濾虛擬/回環介面、多網卡支援。

核心 API 速覽

方法用途
getNetworkInterfaces()列舉所有網路介面
getHardwareAddress()取得 MAC (byte[])
isUp()介面是否啟用
isLoopback()是否回環介面
isVirtual()是否虛擬介面 (Docker、VPN 等)
getMTU()最大傳輸單元
getDisplayName()友善名稱 (如 "Intel 82574L")

工具類完整實作

import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public class MacAddressUtil {

    public static List<String> getAllMacAddresses() {
        List<String> macs = new ArrayList<>();
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            if (interfaces == null) return macs;

            while (interfaces.hasMoreElements()) {
                NetworkInterface ni = interfaces.nextElement();
                if (ni == null) continue;

                // 過濾:啟用、非回環、非虛擬、有實體 MAC
                if (!ni.isUp() || ni.isLoopback() || ni.isVirtual()) continue;
                byte[] macBytes = ni.getHardwareAddress();
                if (macBytes == null || macBytes.length != 6) continue;

                macs.add(formatMac(macBytes));
            }
        } catch (SocketException e) {
            // 記錄日誌,不拋出避免影響主流程
            System.err.println("獲取 MAC 失敗: " + e.getMessage());
        }
        return macs;
    }

    public static String getPrimaryMacAddress() {
        List<String> macs = getAllMacAddresses();
        return macs.isEmpty() ? null : macs.get(0);
    }

    private static String formatMac(byte[] mac) {
        StringBuilder sb = new StringBuilder(17);
        for (int i = 0; i < mac.length; i++) {
            if (i > 0) sb.append(':');
            // 修正:byte 為有號,需 & 0xFF 轉無號再格式化
            sb.append(String.format("%02X", mac[i] & 0xFF));
        }
        return sb.toString();
    }
}

關鍵細節解析

  1. byte 符號陷阱: Java byte 為有號(-128~127),MAC 位元如 0xAB 會變成負數 -85。必須用 mac[i] & 0xFF 轉為無號整數再格式化,否則 Integer.toHexString 會產生 ffffffab。
  2. 格式統一: 採用大寫雙位十六進制 + 冒號分隔(00:1A:2B:3C:4D:5E),符合 IEEE 802 標準,利於資料庫唯一索引與日誌檢索。
  3. 介面過濾策略: 生產環境建議只取 isUp() && !isLoopback() && !isVirtual() 的介面;若需支援 Docker/K8s 環境下的宿主機識別,可保留虛擬介面並結合名稱前綴(eth、ens、bond)判斷。
  4. 多網卡排序: getNetworkInterfaces() 回傳順序不保證。可輔以 getMTU()(實體網卡通常 1500)、getDisplayName() 關鍵字排序,或讓使用者在管理介面確認選擇。

測試輸出範例

// 呼叫
List<String> macs = MacAddressUtil.getAllMacAddresses();
macs.forEach(System.out::println);

// 典型輸出
00:1A:2B:3C:4D:5E   // 實體網卡
00:50:56:C0:00:01   // VMware 虛擬網卡 (若未過濾 isVirtual)
00:50:56:C0:00:08

進階應用:綁定授權檢查

public boolean validateLicense(String licensedMac) {
    String current = MacAddressUtil.getPrimaryMacAddress();
    if (current == null) return false; // 無實體網卡環境(如純容器)需替代方案
    return current.equalsIgnoreCase(licensedMac);
}

注意: 雲主機/容器環境 MAC 可能隨遷移變更,授權體系建議結合 CPUID、磁碟序號、雲廠商 Instance ID 多因子綁定。

常見問題排查

現象原因解決
回傳空列表無實體網卡、權限不足、JVM 安全管理員限制以管理員/root 執行;檢查 SecurityManager 政策
獲取到 00:00:00:00:00:00虛擬介面/隧道介面無實體 MAC加強 isVirtual()、macBytes.length == 6 過濾
Windows 上顯示中文介面名getDisplayName() 回傳本地化名稱僅作顯示用,邏輯判斷用 getName() (如 eth0、Ethernet0)

採用 NetworkInterface 純 Java 方案,一次編寫、到處運行,徹底擺脫指令解析的平台相依與維護負擔。

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