欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java: 获取MAC网络地址

程序员文章站 2022-05-17 08:08:16
...

Java: 获取MAC网络地址

0. 背景

最近由于课程设计,需要使用MAC物理地址作为软件***的唯一标识,故成此博客!

从各个网络适配器的作用 \rightarrow 确定哪一个MAC地址作为唯一标识。在此记录,与诸君分享。

1. 首先打开cmd \rightarrow ipconfig/all ,查看所有MAC地址:

Java: 获取MAC网络地址
Java: 获取MAC网络地址
Java: 获取MAC网络地址
Java: 获取MAC网络地址

2. 博主的ipconfig存在8个网络适配器,故而存在 8 个MAC物理地址。

其中每个网络适配器的含义如下:

Mac网卡地址解析:

  1. Sangfor SSL VPN CS Support System VNIC

    EasyConnect,远程连接VPN应用产生的虚拟网卡。

    具备Mac网卡地址

  2. Realtek PCIe GBE Family Controller

    realtek公司生产的PCIe接口的千兆以太网家用控制器,即 有线网卡

    具备Mac网卡地址

  3. VirtualBox Host-Only Ethernet Adapter

    用于对 虚拟机 进行 通信 的适配器。

    具备Mac网卡地址

  4. Npcap Loopback Adapter

    虚拟网卡,不涉及硬件,它被用于在网络连接不可用时,作为测试虚拟网络环境的工具。

    此外,如果 网络适配器(network adapter) / 网络适配器驱动程序(network adapter driver) 发生冲突,则必须使用 Loopback适配器

    Java中的NetworkInterface中定义:

    loopback interface that only supports communication between entities on this machine.

    本地环回测试的MAC地址,全球所有的计算机相同!!!

    具备Mac网卡地址

  5. Microsoft Wi-Fi Direct Virtual Adapter

    虚拟网卡,使用PC的便携式 热点(hotspot) 共享PC的互联网连接。

    当PC连接无线网,并开启移动热点后,PC会向外发射信号给其他终端,其他终端检测到PC发射出的网络信号,并且可以连接PC发出的无线网络!

    多用于移动设备投屏PC。

    具备Mac网卡地址

  6. Microsoft Wi-Fi Direct Virtual Adapter #2

    Virual Wi-Fi是一种虚拟化网络适配器的技术,一旦被虚拟化,那么,即可将 1 个物理无线适配器转换为 2 个虚拟适配器。

    具备Mac网卡地址

  7. Intel® Dual Band Wireless-AC 3168

    无线网卡

    具备Mac网卡地址

  8. Bluetooth Device (Personal Area Network)

    一种允许创建一个以太网(Ethernet network) 的技术,其允许计算机与移动设备等进行连接。

    局域网(PAN)网卡

    具备Mac网卡地址

3. 了解了各网络适配器的MAC物理地址后,我们可以更加 自信 的编程了!

因为MAC地址数量很多,而虚拟网卡的MAC地址又可以后期修改,只有 无线网卡(Intel® Dual Band Wireless-AC 3168)有限网卡(Realtek PCIe GBE Family Controller) 的MAC物理地址始终无法被改变并且绝大多数电脑都具备这两种网卡;

故,此处选择 无线网卡(Intel® Dual Band Wireless-AC 3168) 的MAC地址作为软件***的唯一标识。

ps:这里说明下,为什么不选择 Npcap Loopback Adapter 的MAC地址作为唯一标识的原因:

因为,全球所有的计算机的 Loopback AdapterMAC地址 都为 02-00-4C-4F-4F-50

而且,因为 MAC地址 位于计算机网络OSI参考模型的 数据链路层 中,其 作用在网络中唯一标示一个网卡,并由此标识唯一计算机,这样,该计算机才能准确的与其他计算机通信

然而, Loopback作用 是用于 本地环回测试,不需要与其他计算机通信,因此其物理地址全球性一致,不具有唯一标识性。

ps: 感兴趣的小朋友可以cmd \rightarrow ipconfig/all 看下,是不是你的 Loopback 的MAC地址 是否与博主一致!????
Java: 获取MAC网络地址

获取MAC地址程序如下:


import sun.encryption.constants.Constants;
import sun.encryption.domain.Network;

import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.List;

import java.util.Enumeration;

public class NetworkUtil {

    /**
     * 一台机器可能存在多个网卡, 故返回数组
     * 网络接口地址(NetworkInterface) ----> 接口地址(InterfaceAddress) ----> IP地址(InetAddress)
     *  ----> 网络接口地址(NetworkInterface)
     * @return
     * @throws Exception
     */
    public static List<Network> getMacAddresses() throws Exception {

        // 获取机器上的所有网络接口, 返回结果至少包含一项(即, loopback本地环回测试)
        // getNetworkInterfaces() + getInetAddresses()可以获取到所有IP地址
        Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();

        StringBuilder sb = new StringBuilder();

        ArrayList<String> networkNames = new ArrayList<String>();

        // 保存mac地址列表
        ArrayList<Network> macList = new ArrayList<Network>();

        // 使用标签, 跳出多重循环
        here:
        while (en.hasMoreElements()) {

            NetworkInterface iface = en.nextElement();

            // 获取对应网络接口的所有接口地址(InterfaceAddress)
            List<InterfaceAddress> addrs = iface.getInterfaceAddresses();

            for (InterfaceAddress addr : addrs) {

                // InetAddress: Internet Protocol (IP) address: IP地址
                // 返回网络接口地址对应的IP地址
                InetAddress ip = addr.getAddress();

                // 由IP地址获取网络接口(NetworkInterface)
                // 方便方法搜索到绑定到其的具体IP地址的网络接口(NetworkInterface)
                NetworkInterface networkInterface = NetworkInterface.getByInetAddress(ip);

                // 若为空, 跳过
                if (networkInterface == null) {

                    continue;

                }

                // 获取以太网等名称, 如:eth0, eth1, wlan1
                String name = networkInterface.getName();

                // 获取描述
                String displayName = networkInterface.getDisplayName();

                // 当网络接口有权限连接, 并且其具有MAC地址时, 返回二进制MAC硬件地址
                byte[] mac = networkInterface.getHardwareAddress();

                // 是否为虚拟网络接口
                boolean virtual = networkInterface.isVirtual();

                // 网络接口是否启动
                boolean up = networkInterface.isUp();

                if (mac == null) {

                    continue;

                }

                // 清空StringBuffer中的内容
                sb.delete(0, sb.length());

                // 转换MAC地址格式
                for (int i = 0; i < mac.length; i++) {

                    sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));

                }

                Network network = new Network();

                // 若网络接口首次出现, 避免返回结果重复
                if (!networkNames.contains(name)) {

                    networkNames.add(name);

                    network.setName(name);
                    network.setDisplayName(displayName);
                    network.setMac(sb.toString());
                    network.setVirtual(virtual);
                    network.setUp(up);

                    macList.add(network);

                }

                // 若找到, 跳出
                if (networkNames.contains(Constants.WIRELESS)) {

                    break here;

                }

            }

        }

        return macList;

    }


    // 根据字符串"wireless"找到对应mac地址
    // 方法有效的条件是: PC机具有无线网卡
    // linux再议
    public static String getWirelessMacAddress() throws Exception {

        List<Network> macs = getMacAddresses();

        for (Network mac: macs) {

            if (mac.getDisplayName().toLowerCase().contains(Constants.WIRELESS)) {

                return mac.getMac();

            }

        }

        return null;

    }




    public static void main(String[] args) throws Exception {

        String wirelessMac = getWirelessMacAddress();
        System.out.println(wirelessMac);

    }

}