java:多网卡环境下获取MAC地址

JDK6以后 java.net.NetworkInterface提供了完整的方法用于获取网络设备信息。 调用 NetworkInterface.getNetworkInterfaces()可以返回所有网络设备 调用NetworkInterface.getHardwareAddress()就可以获取指定网卡的MAC. 下面的完整代码基于NetworkInterface提供了getNICs方法用于获取指定类型设备,通过指定不同的过滤器(Filter.UP,Filter.ALL…)的组合实现过滤条件订制。 提供getMacAddress方法用于获取指定设备的MAC地址

NetworkUtil.java

package net.gdface.facelog.device;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterators;

import com.google.common.base.Predicates;

import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.common.primitives.Bytes;

import com.google.common.base.Function;

/**
 * @author guyadong
 *
 */
public class NetworkUtil {
    public static enum Radix{
        /** 二进制 */BIN(2),
        /** 十进制 */DEC(10),
        /** 十六进制 */HEX(16);
        final int value;
        Radix(int radix){
            this.value = radix;
        }
    }
    public static enum Filter implements Predicate<NetworkInterface>{
        /** 过滤器: 所有网卡 */ALL,
        /** 过滤器: 在线设备,see also {@link NetworkInterface#isUp()} */UP,
        /** 过滤器: 虚拟接口,see also {@link NetworkInterface#isVirtual()} */VIRTUAL,
        /** 过滤器:LOOPBACK, see also {@link NetworkInterface#isLoopback()} */LOOPBACK,
        /** 过滤器:物理网卡 */PHYICAL_ONLY;

        @Override
        public boolean apply(NetworkInterface input) {
            if(null == input ){
                return false;
            }
            try{
                byte[] hardwareAddress;
                switch(this){
                case UP:
                    return input.isUp();
                case VIRTUAL:
                    return input.isVirtual();
                case LOOPBACK:
                    return input.isLoopback();
                case PHYICAL_ONLY :
                    hardwareAddress = input.getHardwareAddress();
                    return null != hardwareAddress 
                            && hardwareAddress.length > 0 
                            && !input.isVirtual() 
                            && !isVMMac(hardwareAddress);
                case ALL:
                default :
                    return true;
                }
            } catch (SocketException e) {
                throw new RuntimeException(e);
            }
        }
    }
    /**
     * 根据过滤器{@code filters}指定的条件(AND)返回网卡设备对象
     * @param filters
     * @return
     */
    @SafeVarargs
    @SuppressWarnings("unchecked")
    public static Set<NetworkInterface> getNICs(Predicate<NetworkInterface> ...filters) {
        if(null == filters){
            filters = new Predicate[]{Filter.ALL};
        }
        try {
            Iterator<NetworkInterface> filtered = Iterators.filter(
                    Iterators.forEnumeration(NetworkInterface.getNetworkInterfaces()),
                    Predicates.and(filters));
            return ImmutableSet.copyOf(filtered);
        } catch (SocketException e) {
            throw new RuntimeException(e);
        } 
    }
    /**
     * 返回所有物理网卡
     * @return
     */
    public static Set<NetworkInterface> getPhysicalNICs() {
        return getNICs(Filter.PHYICAL_ONLY,Filter.UP);
    }
    /**
     * 将{@code byte[]} 转换为{@code radix}指定格式的字符串
     * 
     * @param source 
     * @param separator 分隔符
     * @param radix 进制基数
     * @return {@code source}为{@code null}时返回空字符串
     */
    public static final String format(byte[] source,String separator, final Radix radix) {
        if (null == source){
            return "";
        }
        if(null == separator){
            separator = "";
        }
        List<String> hex = Lists.transform(Bytes.asList(source),new Function<Byte,String>(){
            @Override
            public String apply(Byte input) {
                return String.copyValueOf(new char[]{
                        Character.forDigit((input & 240) >> 4, radix.value),
                        Character.forDigit(input & 15, radix.value)
                });
            }});
        return Joiner.on(separator).join(hex);
    }
    /** 
     * MAC地址格式(16进制)格式化{@code source}指定的字节数组 
     * @see #format(byte[], String, int)
     */
    public static final String formatMac(byte[] source,String separator) {
        return format(source,separator,Radix.HEX);
    }
    /** 
     * 以IP地址格式(点分位)格式化{@code source}指定的字节数组<br>
     * @see #format(byte[], String, int) 
     */
    public static final String formatIp(byte[] source) {
        return format(source,".",Radix.DEC);
    }
    /**
     * 返回指定{@code address}绑定的网卡的物理地址(MAC)
     * @param address
     * @return 指定的{@code address}没有绑定在任何网卡上返回{@code null}
     * @see {@link NetworkInterface#getByInetAddress(InetAddress)}
     * @see {@link NetworkInterface#getHardwareAddress()}
     */
    public static byte[] getMacAddress(InetAddress address) {
        try {
            NetworkInterface nic = NetworkInterface.getByInetAddress(address);
            return null == nic ? null  : nic.getHardwareAddress();
        } catch (SocketException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * @param nic 网卡对象
     * @param separator 格式化分隔符
     * @return 表示MAC地址的字符串
     */
    public static String getMacAddress(NetworkInterface nic,String separator) {
        try {
            return format(nic.getHardwareAddress(),separator, Radix.HEX);
        } catch (SocketException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 参见 {@link #getMacAddress(InetAddress)}
     * @param address
     * @param separator 格式化分隔符
     * @return 表示MAC地址的字符串
     */
    public static String getMacAddress(InetAddress address,String separator) {
        return format(getMacAddress(address),separator, Radix.HEX);     
    }
    private static byte invalidMacs[][] = {
            {0x00, 0x05, 0x69},             // VMWare
            {0x00, 0x1C, 0x14},             // VMWare
            {0x00, 0x0C, 0x29},             // VMWare
            {0x00, 0x50, 0x56},             // VMWare
            {0x08, 0x00, 0x27},             // Virtualbox
            {0x0A, 0x00, 0x27},             // Virtualbox
            {0x00, 0x03, (byte)0xFF},       // Virtual-PC
            {0x00, 0x15, 0x5D}              // Hyper-V
    };
    private static boolean isVMMac(byte[] mac) {
        if(null == mac) {
            return false;
        }

        for (byte[] invalid: invalidMacs){
            if (invalid[0] == mac[0] && invalid[1] == mac[1] && invalid[2] == mac[2]) {
                return true;
            }
        }

        return false;
    }

}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏机器学习入门

挑战程序竞赛系列(87):3.6平面扫描(1)

挑战程序竞赛系列(87):3.6平面扫描(1) 传送门:POJ 2932: Coneology 题意: 平面上有N个两两没有公共点的圆,i号圆的圆心在(xi,...

1908
来自专栏从流域到海域

TensorFlow入门 - 使用TensorFlow给鸢尾花分类(线性模型)

TensorFlow入门 - 使用TensorFlow给鸢尾花分类(线性模型) 本例参考自Plain and Simple Estimators - YouT...

4326
来自专栏Danny的专栏

【项目实战】——Java根据奖品权重计算中奖概率实现抽奖(适用于砸金蛋、大转盘等抽奖活动)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/...

982
来自专栏ml

spring使用Email邮件系统

1.提供邮件信息发送接收,附件绑定功能. 1.配置spring-email.xml文件 <context:property-placeholder loca...

2626
来自专栏编程札记

Kmeans算法解析及基于mapreduce的并行化实现

924
来自专栏窗户

12(13)个球1个不同重量称3次称出的详细分析

  因为网上这道题没有详细思路,我想我还是补个详细思路。这道题目描述是这样的:   有12个一模一样的球,其中11个重量一模一样,剩下的1个重量和其他的不一样。...

1777
来自专栏SnailTyan

枚举——称硬币

1. 枚举 枚举是基于逐个尝试答案的一种问题求解策略。 2. 称硬币(POJ1013) 问题描述 有12枚硬币。其中有11枚真币和1枚假币。假币和真币重量不...

1790
来自专栏一心无二用,本人只专注于基础图像算法的实现与优化。

SSE图像算法优化系列六:OpenCv关于灰度积分图的SSE代码学习和改进。

  最近一直沉迷于SSE方面的优化,实在找不到想学习的参考资料了,就拿个笔记本放在腿上翻翻OpenCv的源代码,无意中看到了OpenCv中关于积分图的代码,仔细...

34910
来自专栏null的专栏

数据结构和算法——用动态规划求解最短路径问题

一、动态规划求解问题的思路     在《算法导论》上,动态规划的求解过程主要分为如下的四步: 描述最优解的结构 递归定义最优解的值 按自底向上的方式计算最优解的...

3345
来自专栏Fish

Android自定义样式listview

这个貌似很常用,以前会了现在正好用到了,所以就复习一下咯。 附上慕课网的视频地址,这个讲得hin详细http://www.imooc.com/learn/365...

1838

扫码关注云+社区