获取本地内网 IP 地址的方法

Java 获取本地内网 IP 地址的方法。

获取本地内网 IP 地址的方法

获取第一个内网 IP

行为特征:

  • 遍历网络接口,返回第一个符合条件的内网 IP
  • 顺序依赖于系统网络接口的枚举顺序
  • 不保证返回的是 "最佳"IP

适用场景: 只需要一个可用的内网 IP,对具体是哪个网段不敏感

/**
 * 获取本地内网IP地址
 * @return 本地内网IP地址
 */
public static String getLocalIntranetIp() {
    try {
        Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
        while (networkInterfaces.hasMoreElements()) {
            NetworkInterface networkInterface = networkInterfaces.nextElement();
            
            // 跳过回环接口和非激活接口
            if (networkInterface.isLoopback() || !networkInterface.isUp()) {
                continue;
            }
            
            Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
            while (inetAddresses.hasMoreElements()) {
                InetAddress inetAddress = inetAddresses.nextElement();
                
                // 只处理IPv4地址且非回环地址
                if (inetAddress instanceof Inet4Address && !inetAddress.isLoopbackAddress()) {
                    String ip = inetAddress.getHostAddress();
                    // 判断是否为内网IP
                    if (isInnerIP(ip)) {
                        return ip;
                    }
                }
            }
        }
    } catch (Exception e) {
        log.error("获取本地内网IP失败", e);
    }
    return "127.0.0.1";
}

获取所有内网 IP

行为特征:

  • 遍历所有网络接口,收集所有内网 IP
  • 包含多网卡、虚拟网卡、VPN 等产生的 IP
  • 提供完整的网络环境视图

适用场景: 需要了解完整网络环境,或让用户选择特定网卡

/**
 * 获取所有本地内网IP地址
 * @return 本地内网IP地址列表
 */
public static List<String> getAllLocalIntranetIps() {
    List<String> ipList = new ArrayList<>();
    try {
        Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
        while (networkInterfaces.hasMoreElements()) {
            NetworkInterface networkInterface = networkInterfaces.nextElement();
            
            // 跳过回环接口和非激活接口
            if (networkInterface.isLoopback() || !networkInterface.isUp()) {
                continue;
            }
            
            Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
            while (inetAddresses.hasMoreElements()) {
                InetAddress inetAddress = inetAddresses.nextElement();
                
                // 只处理IPv4地址且非回环地址
                if (inetAddress instanceof Inet4Address && !inetAddress.isLoopbackAddress()) {
                    String ip = inetAddress.getHostAddress();
                    // 判断是否为内网IP
                    if (isInnerIP(ip)) {
                        ipList.add(ip);
                    }
                }
            }
        }
    } catch (Exception e) {
        log.error("获取所有本地内网IP失败", e);
    }
    return ipList;
}

获取首选内网 IP

行为特征:

  • 智能选择最适合的 IP 地址
  • 优先选择家庭 / 办公室常用的 192.168 网段
  • 避免返回 Docker、VM 等虚拟网络的 IP

适用场景: 需要一个 "最佳" 的本地 IP,用于服务绑定、日志记录等

/**
 * 获取首选的本地内网IP(优先级:192.168.x.x > 10.x.x.x > 172.16-31.x.x)
 * @return 首选的本地内网IP地址
 */
public static String getPreferredLocalIntranetIp() {
    List<String> ipList = getAllLocalIntranetIps();
    if (ipList.isEmpty()) {
        return "127.0.0.1";
    }
    
    // 优先返回192.168网段的IP
    for (String ip : ipList) {
        if (ip.startsWith("192.168.")) {
            return ip;
        }
    }
    
    // 其次返回10网段的IP
    for (String ip : ipList) {
        if (ip.startsWith("10.")) {
            return ip;
        }
    }
    
    // 最后返回172.16-31网段的IP
    for (String ip : ipList) {
        if (ip.startsWith("172.")) {
            String[] parts = ip.split("\\.");
            if (parts.length >= 2) {
                int secondOctet = Integer.parseInt(parts[1]);
                if (secondOctet >= 16 && secondOctet <= 31) {
                    return ip;
                }
            }
        }
    }
    
    // 如果都没有,返回第一个
    return ipList.get(0);
}

其他补充方法

/**
 * 获取本地主机名
 * @return 本地主机名
 */
public static String getLocalHostName() {
    try {
        return InetAddress.getLocalHost().getHostName();
    } catch (UnknownHostException e) {
        log.error("获取本地主机名失败", e);
        return "unknown";
    }
}

/**
 * 获取本地IP和主机名信息
 * @return 格式为 "IP(hostname)" 的字符串
 */
public static String getLocalIpWithHostName() {
    String ip = getPreferredLocalIntranetIp();
    String hostname = getLocalHostName();
    return ip + "(" + hostname + ")";
}

完整的导入语句

在文件顶部添加这些导入:

import java.net.NetworkInterface;
import java.net.Inet4Address;
import java.util.Enumeration;
import java.util.ArrayList;

使用示例

public static void main(String[] args) {
    // 获取单个内网IP
    String localIp = getLocalIntranetIp();
    log.info("本地内网IP: {}", localIp);
    
    // 获取所有内网IP
    List<String> allIps = getAllLocalIntranetIps();
    log.info("所有本地内网IP: {}", allIps);
    
    // 获取首选内网IP
    String preferredIp = getPreferredLocalIntranetIp();
    log.info("首选内网IP: {}", preferredIp);
    
    // 获取主机名
    String hostname = getLocalHostName();
    log.info("本地主机名: {}", hostname);
    
    // 获取IP和主机名
    String ipWithHostname = getLocalIpWithHostName();
    log.info("IP和主机名: {}", ipWithHostname);
}

这些方法会自动过滤掉回环地址和非内网地址,返回真正的本地内网 IP 地址。getPreferredLocalIntranetIp() 方法按照常用网段的优先级返回最合适的 IP 地址。

典型场景下的不同结果

场景 1:普通家用电脑

第一个内网IP: 192.168.1.100
所有内网IP: [192.168.1.100]
首选内网IP: 192.168.1.100
结果: 三个方法返回相同

场景 2:开发者电脑(Docker + VPN)

第一个内网IP: 172.17.0.1      (Docker网桥)
所有内网IP: [172.17.0.1, 10.0.2.15, 192.168.1.100]
首选内网IP: 192.168.1.100     (优先选择192.168网段)
结果: 首选方法返回更合适的IP

场景 3:服务器(多网卡)

第一个内网IP: 10.0.1.50       (第一个网卡)
所有内网IP: [10.0.1.50, 192.168.100.10, 172.20.0.5]
首选内网IP: 192.168.100.10    (优先192.168网段)
结果: 首选方法选择了业务网段

推荐使用场景

方法 适用场景 优点 缺点
getLocalIntranetIp() 简单应用,只需一个 IP 快速、简单 可能返回虚拟网络 IP
getAllLocalIntranetIps() 网络诊断、用户选择 信息完整 需要额外处理逻辑
getPreferredLocalIntranetIp() 服务绑定、配置生成 智能选择 逻辑相对复杂

建议: 大多数情况下使用 getPreferredLocalIntranetIp(),它能提供最合适的结果。