知道InetAddress.getLocalHost()方法是可以获取本地ip的,但是在mac电脑上执行的时候,偶尔会得到127.0.0.1的输出,这样拿到本地ip很不稳定,感觉就很不靠谱了

InetAddress.getLocalHost()方法获取本地IP不靠谱

代码

    public static void main(String[] args) throws Exception {
        InetAddress addr = InetAddress.getLocalHost();
        System.out.println("Local HostAddress: "+addr.getHostAddress());
        String hostname = addr.getHostName();
        System.out.println("Local host name: "+hostname);
    }

mac上输出
在这里插入图片描述

原因

windows环境: 使用InetAddress.getLocalHost()方法看似正常能获得本地ip,实际也有不确定性(多网卡协同工作环境下是不准确的

Java 的InetAddress.java 调用 InetAddressImpl.java 的 public native String getLocalHostName() throws UnknownHostException;来获取本地主机名,是一个系统原生方法和ping hostname 返回的 IP 地址是同一个,并不是 ipconfig 方法得到的 eth0 的IP 地址.

默认情况下本机名是localhost,在host文件中对应的ip是127.0.0.1,所以通过这个函数获取到的ip就是127.0.0.1了

即它就是简单的读取/etc/hosts的内容,所以它默认返回的是127.0.0.1非常的不靠谱,因此本方法十分不建议在生产上使用。

不如我们来看一下 /etc/hosts

在这里插入图片描述

/etc/hosts的第一行一般均是:127.0.0.1 localhost,所以返回值是127.0.0.1(倘若你把第一行改为127.1.1.1 localhost,那么它的返回值就是127.1.1.1了)

获取本地IP的靠谱方法

从JDK1.4开始,Java提供了一个NetworkInterface类。这个类可以得到本机所有的物理网络接口和虚拟机等软件利用本机的物理网络接口创建的逻辑网络接口的信息,NetworkInterface可以通过getNetworkInterfaces方法来枚举本机所有的网络接口。我们也可以利用getNetworkInterfaces得到的网络接口来枚举本机的所有IP地址。

NetworkInterface类提供了三个方法可以分别得到网络接口名(getName方法)、网络接口别名(getDisplayName方法)以及和网络接口绑定的所有IP地址(getInetAddresses方法)

代码

windows和linux下通用的获取本机IP的方法

package test;

import java.io.IOException;
import java.net.*;
import java.util.Enumeration;

/**
 * @author yanZhiHang
 * @date 2023/2/2 11:59
 */
public class GetLocalHost {
    public static void main(String[] args) throws Exception {
        InetAddress addr = InetAddress.getLocalHost();
        System.out.println("Local HostAddress: "+addr.getHostAddress());
        String hostname = addr.getHostName();
        System.out.println("Local host name: "+hostname);
        System.out.println("本机ip:" + getIpAddress());
    }

    public static String getIpAddress() {
        try {
            //从网卡中获取IP
            Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
            InetAddress ip;
            while (allNetInterfaces.hasMoreElements()) {
                NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
                //用于排除回送接口,非虚拟网卡,未在使用中的网络接口
                if (!netInterface.isLoopback() && !netInterface.isVirtual() && netInterface.isUp()) {
                //返回和网络接口绑定的所有IP地址
                    Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
                    while (addresses.hasMoreElements()) {
                        ip = addresses.nextElement();
                        if (ip instanceof Inet4Address) {
                            return ip.getHostAddress();
                        }
                    }
                }
            }
        } catch (Exception e) {
            System.err.println("IP地址获取失败" + e.toString());
        }
        return "";
    }
}

避坑

注意代码中是返回和网络接口绑定的所有IP地址

⚠️我这边服务器有docker容器,结果根据上述代码获取本地IP的时候,获取的是docker对外的网卡ip,结果导致获取先获取到了docker对外的网卡ip。同时也有可能存在多个网卡,影响获取真正的IP

解决

因为我真实目的是校验输入的IP是否为本机ip,所以只要证明网络接口中的所有IP包含输入的IP即可

改造后的代码

    public static boolean isLocalHost(String localHost) throws Exception {
        try {
            Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
            while (allNetInterfaces.hasMoreElements()) {
                NetworkInterface netInterface = allNetInterfaces.nextElement();
                if (!netInterface.isLoopback() && !netInterface.isVirtual() && netInterface.isUp()) {
                    Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
                    while (addresses.hasMoreElements()) {
                        InetAddress ip = addresses.nextElement();
                        if (null != ip && ip.getHostAddress().contains(localHost)) {
                            return true;
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("校验IP地址失败:", e.getCause());
            e.printStackTrace();
            throw new Exception(e);
        }
        return false;
    }

参考
java获取本机IP

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐