Skip to content

动态获取当前服务器的IP地址

问题分析

  1. getLocalHost() 的局限性
    • 依赖系统的主机名解析,若 /etc/hosts 或 DNS 配置不当,可能返回 127.0.0.1 或错误 IP。
    • 在容器(如 Docker)中运行时,可能返回容器内 IP 而非宿主机 IP。
  2. 多网卡环境
    • 若机器有多个网络接口(如以太网、Wi-Fi、虚拟网卡),可能无法获取到预期的公网或内网 IP。

遍历所有网络接口,筛选符合条件的 IP

java
package robot.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * @author zhangch
 * @version 1.0
 * @date 2025/5/10 13:33
 * @description
 */
public class NetworkUtils {
    private static final Logger log = LoggerFactory.getLogger(NetworkUtils.class);
    // 统一获取 IP 地址(适配多环境)
    public static String getAdaptiveIp() {
        if (EnvironmentUtils.isRunningInDocker()) {
            // Docker 环境优先读取宿主机的 HOST_IP 环境变量
            String hostIp = System.getenv("HOST_IP");
            if (hostIp != null) return hostIp;
            // 使用特定网络名称获取IP地址
            if (getOvsIp() != null) return getOvsIp();
        }
        // 物理机环境使用通用 IP 获取逻辑
        return getLocalIp();
    }
    private static String getOvsIp() {
        try {
            NetworkInterface ovsInterface = NetworkInterface.getByName("ovs_eth0");
            if (ovsInterface != null && ovsInterface.isUp()) {
                Enumeration<InetAddress> addresses = ovsInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress addr = addresses.nextElement();
                    if (addr instanceof Inet4Address && !addr.isLoopbackAddress()) {
                        return addr.getHostAddress();
                    }
                }
            }
        } catch (SocketException e) {
            log.error("Failed to access network interfaces: {}", e.getMessage());
            throw new RuntimeException(e);
        }
        return null;
    }
    /**
     * 获取本机有效 IPv4 地址(排除回环地址、虚拟接口等)
     */
    private static String getLocalIp() {
        try {
            List<String> ipList = new ArrayList<>();
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();

            while (interfaces.hasMoreElements()) {
                NetworkInterface iface = interfaces.nextElement();
                // 排除虚拟接口、未启用的接口
                if (iface.isLoopback() || !iface.isUp() || iface.isVirtual()) {
                    continue;
                }

                Enumeration<InetAddress> addresses = iface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress addr = addresses.nextElement();
                    // 仅处理 IPv4 地址
                    if (addr instanceof Inet4Address) {
                        String ip = addr.getHostAddress();
                        // 排除 127.0.0.1 等回环地址
                        if (!addr.isLoopbackAddress()) {
                            ipList.add(ip);
                        }
                    }
                }
            }
            if (!ipList.isEmpty()) {
                // 返回第一个非回环地址,或按需选择特定 IP
                return ipList.get(0);
            } else {
                return "127.0.0.1";
                //throw new RuntimeException("No valid IPv4 address found");
            }
        } catch (SocketException e) {
            log.error("Failed to get network interfaces: {}", e.getMessage());
            throw new RuntimeException(e);
        }
    }
}
java
package robot.util;

import java.io.File;

/**
 * @author zhangch
 * @version 1.0
 * @date 2025/5/10 13:35
 * @description
 */
public class EnvironmentUtils {
    // 检测是否运行在 Docker 容器中
    public static boolean isRunningInDocker() {
        File dockerEnvFile = new File("/.dockerenv");
        return dockerEnvFile.exists();
    }

    // 获取操作系统类型
    public static String getOsType() {
        String os = System.getProperty("os.name").toLowerCase();
        if (os.contains("win")) {
            return "windows";
        } else if (os.contains("nix") || os.contains("nux")) {
            return "linux";
        } else {
            return "other";
        }
    }
}

使用示例

java
try {
    String ip = NetworkUtils.getLocalIp();
    log.info("本机 IP: {}", ip);
} catch (RuntimeException e) {
    log.error("获取 IP 失败", e);
    // 降级处理(如使用默认值)
    String fallbackIp = "127.0.0.1";
}

关键改进点

优化项说明
多网卡支持遍历所有网络接口,避免依赖单一接口
过滤无效地址排除回环地址 (127.0.0.1)、虚拟接口、未启用接口
明确 IPv4 优先通过 Inet4Address 确保只获取 IPv4 地址
异常处理统一捕获 SocketException,日志记录更清晰
可扩展性返回 IP 列表 (ipList),方便后续按需选择(如优先选择内网/外网地址)

扩展场景处理

  1. 容器环境

    • 若在 Docker 中运行,需确保获取的是容器对外的 IP(通常通过环境变量传递,如 HOST_IP)。
  2. **IPv6 支持

    java
    if (addr instanceof Inet6Address) {
        // 处理 IPv6 逻辑
    }

上次更新于:

本站已运行: