详细分析Java中的NetworkInterface类(附Demo)

本文详细介绍了Java中的NetworkInterface类,包括其基本知识、源码解读以及常用API,重点讲解了获取网络接口信息、IP地址、MAC地址的方法,同时讨论了类的优缺点和权限检查机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

对于Java的基本知识推荐阅读:

  1. java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
  2. 【Java项目】实战CRUD的功能整理(持续更新)

1. 基本知识

NetworkInterface 类是 Java 中用于表示网络接口的类,它提供了一系列方法来获取有关网络接口的信息

核心概念如下:

  • 本地计算机的网络接口,可以是物理接口(如网卡)或虚拟接口(如回环接口)
  • 每个网络接口都有一个唯一的名称和一个或多个 IP 地址,还可能有一个硬件地址(MAC 地址)
  • 多个网络接口,每个网络接口都有一个唯一的索引,网络接口的名称是一个描述性的字符串

涉及的优缺点如下(针对自身功能,是否满足该类从而往下阅读):

  1. 优点:
  • 跨平台性:无论应用程序运行在哪种操作系统上,都可以使用 NetworkInterface 类来获取网络接口信息
  • 封装性:封装了底层操作系统提供的获取网络接口信息的细节,无需关心不同操作系统下的具体实现细节,只需要使用统一的 Java API 接口即可
  • 简单易用:简单易用的方法来获取网络接口的名称、IP 地址和 MAC 地址等信息,可以轻松地集成网络接口信息获取功能到自己的应用程序中
  1. 缺点
  • 限制性:只能获取到一些基本的网络接口信息,如名称、IP 地址和 MAC 地址等,不能获取更多详细的网络配置信息

  • 不足的操作系统支持:不同版本的操作系统可能支持的功能不同。例如,在某些旧版本的操作系统上可能无法获取到完整的网络接口信息

2. 源码解读

解读几个比较常用的API接口源码

一、 getNetworkInterfaces函数

获取本地计算机的所有网络接口,并返回一个 Enumeration<NetworkInterface> 对象,包含了所有网络接口的实例
2. 调用 getAll() 方法获取本地计算机的所有网络接口,并将结果存储在 netifs 数组中
3. Enumeration 对象的 nextElement() 方法中,逐个返回 netifs 数组中的网络接口实例,hasMoreElements() 方法中,检查是否还有更多的网络接口未返回
4. 遍历所有网络接口:nextElement() 方法中,通过 i 记录当前遍历到的网络接口的索引等

public static Enumeration<NetworkInterface> getNetworkInterfaces()
    throws SocketException {
    final NetworkInterface[] netifs = getAll();

    // specified to return null if no network interfaces
    if (netifs == null)
        return null;

    return new Enumeration<NetworkInterface>() {
        private int i = 0;
        public NetworkInterface nextElement() {
            if (netifs != null && i < netifs.length) {
                NetworkInterface netif = netifs[i++];
                return netif;
            } else {
                throw new NoSuchElementException();
            }
        }

        public boolean hasMoreElements() {
            return (netifs != null && i < netifs.length);
        }
    };
}

二、getInetAddresses函数

获取网络接口的所有 IP 地址,并返回一个 Enumeration<InetAddress> 对象,包含了网络接口的所有 IP 地址的实例

  1. 权限检查:在构造方法中, System.getSecurityManager() 获取安全管理器,检查是否有 NetPermission("getNetworkInformation") 权限。如果存在安全管理器且没有相应的权限,则标记为不受信任。然后遍历所有的 IP 地址,如果安全管理器存在且不受信任,还需要检查是否有连接到这些 IP 地址的权限。只有通过了权限检查的 IP 地址才会被保存在 local_addrs 数组中
  2. 实现 nextElement() 方法:在 checkedAddresses 内部类中实现了 nextElement() 方法,用于返回下一个 IP 地址
  3. 实现 hasMoreElements() 方法:在 checkedAddresses 内部类中实现了 hasMoreElements() 方法,用于判断是否还有更多的 IP 地址未返回
public Enumeration<InetAddress> getInetAddresses() {

    class checkedAddresses implements Enumeration<InetAddress> {
		/**
		* 初始化了一些变量,包括 i(当前遍历到的索引)
		* count(实际有效的 IP 地址数量)
		* local_addrs(存储 IP 地址的数组)
		*/
        private int i=0, count=0;
        private InetAddress local_addrs[];

        checkedAddresses() {
            local_addrs = new InetAddress[addrs.length];
            boolean trusted = true;

            SecurityManager sec = System.getSecurityManager();
            if (sec != null) {
                try {
                    sec.checkPermission(new NetPermission("getNetworkInformation"));
                } catch (SecurityException e) {
                    trusted = false;
                }
            }
            for (int j=0; j<addrs.length; j++) {
                try {
                    if (sec != null && !trusted) {
                        sec.checkConnect(addrs[j].getHostAddress(), -1);
                    }
                    local_addrs[count++] = addrs[j];
                } catch (SecurityException e) { }
            }

        }

        public InetAddress nextElement() {
            if (i < count) {
                return local_addrs[i++];
            } else {
                throw new NoSuchElementException();
            }
        }

        public boolean hasMoreElements() {
            return (i < count);
        }
    }
    return new checkedAddresses();

}

三、getHardwareAddress函数

获取网络接口的硬件地址(MAC 地址)

  1. 权限检查:System.getSecurityManager() 获取安全管理器 sec。如果安全管理器不为空,则尝试检查是否有 NetPermission("getNetworkInformation") 权限。如果没有该权限,会捕获 SecurityException 异常。如果没有该权限,并且当前网络接口没有更多的 IP 地址,说明无法获取到任何本地地址的连接权限,则直接返回 null
  2. 遍历 IP 地址:遍历网络接口的所有 IP 地址
  3. 调用底层方法:如果没有找到 IPv4 地址,则调用 getMacAddr0() 方法,并将参数传递为 null,意味着将尝试获取任意地址的 MAC 地址
public byte[] getHardwareAddress() throws SocketException {
    SecurityManager sec = System.getSecurityManager();
    if (sec != null) {
        try {
            sec.checkPermission(new NetPermission("getNetworkInformation"));
        } catch (SecurityException e) {
            if (!getInetAddresses().hasMoreElements()) {
                // don't have connect permission to any local address
                return null;
            }
        }
    }
    for (InetAddress addr : addrs) {
        if (addr instanceof Inet4Address) {
            return getMacAddr0(((Inet4Address)addr).getAddress(), name, index);
        }
    }
    return getMacAddr0(null, name, index);
}

四、getByInetAddress函数

类中的 getByInetAddress(InetAddress addr) 方法的实现部分,用于根据给定的 InetAddress 地址获取对应的 NetworkInterface 实例

地址类型检查: instanceof 关键字判断传入的地址是 IPv4 地址还是 IPv6 地址。

public static NetworkInterface getByInetAddress(InetAddress addr) throws SocketException {
    if (addr == null) {
        throw new NullPointerException();
    }
    if (addr instanceof Inet4Address) {
        Inet4Address inet4Address = (Inet4Address) addr;
        if (inet4Address.holder.family != InetAddress.IPv4) {
            throw new IllegalArgumentException("invalid family type: "
                    + inet4Address.holder.family);
        }
    } else if (addr instanceof Inet6Address) {
        Inet6Address inet6Address = (Inet6Address) addr;
        if (inet6Address.holder.family != InetAddress.IPv6) {
            throw new IllegalArgumentException("invalid family type: "
                    + inet6Address.holder.family);
        }
    } else {
        throw new IllegalArgumentException("invalid address type: " + addr);
    }
    return getByInetAddress0(addr);
}

3. 常用API

一、getNetworkInterfaces()

  • NetworkInterface 类的静态方法,获取本地计算机的所有网络接口
  • 返回一个 Enumeration<NetworkInterface> 对象,包含本地计算机的所有网络接口的实例

示例代码:

Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
    NetworkInterface networkInterface = interfaces.nextElement();
    // 处理每个网络接口
}

二、getDisplayName()

  • 获取网络接口的名称
  • 返回值为 String 类型,表示网络接口的名称

示例代码:

String interfaceName = networkInterface.getDisplayName();
System.out.println("Network Interface Name: " + interfaceName);

三、getInetAddresses()

  • 获取网络接口的所有 IP 地址
  • 返回一个 Enumeration<InetAddress> 对象,其中包含了网络接口的所有 IP 地址的实例

示例代码:

Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
    InetAddress address = addresses.nextElement();
    // 处理每个 IP 地址
}

四、getHardwareAddress()

  • 获取网络接口的硬件地址(MAC 地址)
  • 返回一个 byte[] 数组,表示 MAC 地址的字节表示形式

示例代码:

byte[] macAddress = networkInterface.getHardwareAddress();
if (macAddress != null) {
    StringBuilder sb = new StringBuilder();
    for (byte b : macAddress) {
        sb.append(String.format("%02X-", b));
    }
    System.out.println("MAC Address: " + sb.toString());
}

五、getIndex()

  • 获取网络接口的索引
  • 返回一个 int 值,表示网络接口的索引

示例代码:

int index = networkInterface.getIndex();
System.out.println("Interface Index: " + index);

六、isUp()

  • 判断网络接口是否已经启用(处于 up 状态)
  • 返回一个 boolean 值,表示网络接口是否已经启用

示例代码:

boolean isUp = networkInterface.isUp();
System.out.println("Interface is Up: " + isUp);

4. Demo

对应的Demo推荐阅读(用NetworkInterface类之前也会比较CMD的差异):

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

码农研究僧

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

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

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

打赏作者

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

抵扣说明:

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

余额充值