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;
    }

}

测试代码参见码云仓库:

https://gitee.com/l0km/common-java/blob/master/common-base2/src/test/java/net/gdface/utils/NetworkUtilTest.java

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

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

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值