【代码打假】java如何获取mac物理地址?

前言

原本以为这功能调用一个api就完事了,然而,查了一下没那么简单,网上查的资料实在忍不住要拿出来说说,估计真的都没有试过其他环境,而且,估计连背后的原理都没了解就用了。。
下面先说说找到的几份资料:

ps:本机相关ip信息:
在这里插入图片描述

第一篇参考

Java获取本机MAC地址

点评:实际运行效果如下:
在这里插入图片描述
空指针啊。。。那么我们如果换个ip来试试?

第二篇参考

使用java获取本机mac

看看代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class getmac{
public static String getLinuxMACAddress() {
        String mac = null;
        BufferedReader bufferedReader = null;
        Process process = null;
        try {            
            process = Runtime.getRuntime().exec("ifconfig enp4s0");
            bufferedReader = new BufferedReader(new InputStreamReader(
                    process.getInputStream()));
            String line = null;
            int index = -1;
            while ((line = bufferedReader.readLine()) != null) {
                index = line.toLowerCase().indexOf("硬件地址");
                
                if (index != -1) {
                    
                    mac = line.substring(index + 4).trim();
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            bufferedReader = null;
            process = null;
        }
        return mac;
    }
public static void main(String[] argc) {
    String mac = getLinuxMACAddress();
    System.out.println("本地是Linux系统, MAC地址是:" + mac);

}
}

一运行:
在这里插入图片描述

还是不行。。里面几行代码我有点在意:

process = Runtime.getRuntime().exec("ifconfig enp4s0");



index = line.toLowerCase().indexOf("硬件地址");

调用命令ifconfig enp4s0 然后根据字符串“硬件地址”来截取字符,获得mac地址

这样做估计不行,部署到正式环境分分钟挂掉机器

首先:
不同机器的enp这些东西是不一样的:
在这里插入图片描述
其次,“硬件地址”这个字符串估计在不同机器上面有不同的解释吧。。。

第三份资料

How can i get list of MAC address and IP address of computer through java?

为了方便查看,我抄一下【墙的强度略大,google的js脚本都卡掉了,估计大家都是卡五六分钟才看到的,我懂】

在这里插入图片描述

在这里插入图片描述

两段代码如下:

           InetAddress ip;
    ip = InetAddress.getLocalHost();
    System.out.println("Current IP address : " + ip.getHostAddress());

    NetworkInterface network = NetworkInterface.getByInetAddress(ip);

    byte[] mac = network.getHardwareAddress();

    System.out.print("Current MAC address : ");

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < mac.length; i++) {
        sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));        
    }
    System.out.println(sb.toString());

                    java.util.Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
        en.hasMoreElements(); ) {
        NetworkInterface iface = en.nextElement();
        List<InterfaceAddress> addrs = iface.getInterfaceAddresses();
        //For each network interfaces iterate through each ip address
        for(InterfaceAddress addr : addrs) {
                         ip = addr.getAddress();
                          //Process the IP ...

好了,根据以上回答及代码,补充完整,然后查看结果

单地址:

package test;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;

public class SingleNetAddress {
    /*
     * @param args
     * @throws UnknownHostException
     * @throws SocketException
     */
    public static void main(String[] args) throws UnknownHostException, SocketException {



        System.out.println("进行single net address 测试===》");

        InetAddress ip;
        ip = InetAddress.getLocalHost();
        System.out.println("Current IP address : " + ip.getHostAddress());

        NetworkInterface network = NetworkInterface.getByInetAddress(ip);

        byte[] mac = network.getHardwareAddress();

        System.out.print("Current MAC address : ");

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < mac.length; i++) {
            sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
        }
        System.out.println(sb.toString());

    }
}

运行结果:

在这里插入图片描述

不行,还是出错了。。

多地址的:

package test;

import java.net.*;
import java.util.List;

public class MultiNetAddress {
    /*
     * @param args
     * @throws UnknownHostException
     * @throws SocketException
     */
    public static void main(String[] args) throws UnknownHostException, SocketException {
        System.out.println("进行 multi net address 测试===》");
        java.util.Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
        while(en.hasMoreElements()){
            NetworkInterface iface = en.nextElement();
            List<InterfaceAddress> addrs = iface.getInterfaceAddresses();
            //For each network interfaces iterate through each ip address
            //For each network interfaces iterate through each ip address
            for(InterfaceAddress addr : addrs) {
                InetAddress  ip = addr.getAddress();
                System.out.println("Current IP address : " + ip.getHostAddress());

                NetworkInterface network = NetworkInterface.getByInetAddress(ip);

                byte[] mac = network.getHardwareAddress();

                System.out.print("Current MAC address : ");

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < mac.length; i++) {
                    sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
                }
                System.out.println(sb.toString());
            }
        }


    }
}

运行结果:
在这里插入图片描述

欸,有点意思了,已经接近需要的结果了,看看之前本机的ifconfig的值:
在这里插入图片描述
起码蒙对了一个,不过enp3s0的还是没读出来。突破口就在这里。

下面查一查ifconfig下面的各个含义是什么。。我到现在都不明白这些含义,估计一天不弄清楚一天都没办法获得真正的物理地址了。
Linux网卡命名enp3s0说明
在这里插入图片描述

还有一篇:
linux下eth0 lo wlan0

在这里插入图片描述
在这里插入图片描述
通过阅读可以理解到,ifconfig在每个系统出来的名称还有格式估计都是有差别的。用字符串识别提取方式来获得mac地址估计。。。真的不行。mac地址在linux下面也是可以修改的。

而且:
en eth 都是本地网卡,有mac地址
lo是localhost,本机地址—这个不属于网卡吧,没有mac地址的吧?
wlan wl意思是无线网卡,也有mac地址。

我的是手提电脑,当然有无线网卡也有本地网卡。。额,这样就解释了:

enp3s0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        ether d8:c4:97:43:41:2f  txqueuelen 1000  (以太网)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (本地环回)
        RX packets 4067  bytes 537739 (537.7 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 4067  bytes 537739 (537.7 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wlp5s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.0.102  netmask 255.255.255.0  broadcast 192.168.0.255
        inet6 fe80::136b:f8d9:d35:b59  prefixlen 64  scopeid 0x20<link>
        ether 68:ec:c5:c4:d1:96  txqueuelen 1000  (以太网)
        RX packets 107772  bytes 149800655 (149.8 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 26297  bytes 4348455 (4.3 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0


wlp5s0 无线网卡 有ip地址,ipv4: inet 192.168.0.102 ipv6: inet6 fe80::136b:f8d9:d35:b59 mac地址:68:ec:c5:c4:d1:96

而 enp3s0 内置网卡没有 ipv4,也没有ipv6地址,mac地址:d8:c4:97:43:41:2f

因为没有接网线啊,接的是无线。

lo 没有mac地址,ipv4为:127.0.0.1 ipv6为: ::1

网线网卡测试

为了求证上面结论,那么下面来做基本的试验,

笔记本用无线上网,没有插入网线

在这里插入图片描述

笔记本用禁用无线上网,插入网线

在这里插入图片描述

欸,wl不见了,en有ip地址了。。

笔记本用启用无线上网,插入网线

在这里插入图片描述
en,wl同时存在,都有ip地址。

而lo一直没有mac地址,ip地址一直是本地。就是说,java 获取本机ipmac时候,获取到本机lo的地址然后肯定没办法获得mac地址咯?

其他电脑ifconfig的表现

为了验证lo是不是不会有mac地址,特意查看其他人其他机器的表现,如下:
linux命令之ifconfig详细解释

在这里插入图片描述

估计lo真的是不会有mac地址了。。共性。所以现在的问题在于,如何遍历获取多个网卡的mac地址?

优化获取代码,不同情况进行试验

好了,现在来优化一下代码,在不同情况下运行程序进行测试:

代码如下:

package test;

import java.net.*;
import java.util.List;

public class MultiNetAddress {
    /*
     * @param args
     * @throws UnknownHostException
     * @throws SocketException
     */
    public static void main(String[] args) throws UnknownHostException, SocketException {
        System.out.println("进行 multi net address 测试===》");
        java.util.Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
        while(en.hasMoreElements()){
            NetworkInterface iface = en.nextElement();
            List<InterfaceAddress> addrs = iface.getInterfaceAddresses();
            //For each network interfaces iterate through each ip address
            //For each network interfaces iterate through each ip address
            for(InterfaceAddress addr : addrs) {
                InetAddress  ip = addr.getAddress();
                System.out.println("Current IP address : " + ip.getHostAddress());

                NetworkInterface network = NetworkInterface.getByInetAddress(ip);

                if(network==null){
                    System.out.println("真遗憾,系统无法获取"+ip+" 的network对象!!");
                }
                else{
                    byte[] mac = network.getHardwareAddress();

                    System.out.print("Current MAC address : ");

                    StringBuilder sb = new StringBuilder();
                    if(mac==null)
                    {
                        System.out.println("真遗憾,系统无法获取"+ip+" 的mac地址");
                    }
                    else{
                        for (int i = 0; i < mac.length; i++) {
                            sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
                        }
                        System.out.println(sb.toString());
                    }
                }

            }
        }


    }
}

情况一、不接网线,开启连接无线网络

ifconfig结果:
在这里插入图片描述

程序运行结果:
在这里插入图片描述

第二种情况,连接网线,开启并连接无线

ifconfig结果:
在这里插入图片描述

程序运行结果

在这里插入图片描述

第三种情况,连接网线,关闭无线

ifconfig结果

在这里插入图片描述

运行情况:

在这里插入图片描述

第四种情况,拔出网线,关闭无线

ifconfig结果:
在这里插入图片描述
运行结果:
在这里插入图片描述

获取mac地址的结论

在这几种情况下面

getNetworkInterfaces

返回的分别的肯定有,lo—即localhost连接,
如果eth–内置网卡—有连接网线的话,那么就会包括etch,
如果wlan–无线—有连接的话,那么也会包括wlan。

getInterfaceAddresses

会返回ipv4,以及ipv6的地址,对于lo这个networkinterface来说,会返回:
ipv6 0:0:0:0:0:0:0:1%lo 以及ipv4 127.0.0.1,遗憾的是:
lo的ipv6永远是连接不上的,network是null,而ipv4连接上了也是没有mac地址的,
基本上来说,linux下面是不能通过lo来获取mac的,windows下面不清楚
在这里插入图片描述

而其他两个,只要连接上了—eth以及wlan,只要连接上了就能获得mac地址:

Current IP address : fe80:0:0:0:136b:f8d9:d35:b59%wlp5s0
Current MAC address : 68-EC-C5-C4-D1-96
Current IP address : 192.168.0.102
Current MAC address : 68-EC-C5-C4-D1-96
Current IP address : fe80:0:0:0:d029:29c1:936c:64c9%enp3s0
Current MAC address : D8-C4-97-43-41-2F
Current IP address : 192.168.0.101
Current MAC address : D8-C4-97-43-41-2F

无论是ipv4还是ipv6

所以,现在心里面应该有底了,那就是,如何获取mac地址?

mac地址的获取通用代码

package test;

import java.net.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

public class MacTools {
    /***因为一台机器不一定只有一个网卡呀,所以返回的是数组是很合理的***/
    public static List<String> getMacList() throws Exception {
        java.util.Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
        StringBuilder sb = new StringBuilder();
        ArrayList<String> tmpMacList=new ArrayList<>();
        while(en.hasMoreElements()){
            NetworkInterface iface = en.nextElement();
            List<InterfaceAddress> addrs = iface.getInterfaceAddresses();
            for(InterfaceAddress addr : addrs) {
                InetAddress ip = addr.getAddress();
                NetworkInterface network = NetworkInterface.getByInetAddress(ip);
                if(network==null){continue;}
                byte[] mac = network.getHardwareAddress();
                if(mac==null){continue;}
                sb.delete( 0, sb.length() );
                for (int i = 0; i < mac.length; i++) {sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));}
                tmpMacList.add(sb.toString());
            }        }
        if(tmpMacList.size()<=0){return tmpMacList;}
        /***去重,别忘了同一个网卡的ipv4,ipv6得到的mac都是一样的,肯定有重复,下面这段代码是。。流式处理***/
        List<String> unique = tmpMacList.stream().distinct().collect(Collectors.toList());
        return unique;
    }
    public static void main(String[] args) throws Exception {
        System.out.println("进行 multi net address 测试===》");
        List<String> macs=getMacList();
        System.out.println("本机的mac网卡的地址有:"+macs);

    }
}

运行结果:
在这里插入图片描述

后语

话说,真自豪。能够有理有据,各个情况都有考虑,将mac地址的获取清楚说出来的,恐怕不多。很多都是开局一段码,结果全靠蒙。
希望上面的东西能够帮到你、

©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页

打赏作者

码农下的天桥

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值