InetAddress.getLocalHost()不可靠,因其依赖主机名+DNS反向解析,易返回127.0.0.1或抛异常;应遍历NetworkInterface筛选非回环IPv4地址,并用Runtime.exec("hostname")或环境变量获取主机名。
直接用
获取本机 IP 和主机名看似简单,但实际运行中经常返回
或抛出
,根本原因在于它不查网卡,而是依赖系统主机名 + DNS 反向解析——这一步极易断裂。真正稳定可用的方式需要组合判断和主动筛选。
获取真实局域网 IPv4 地址(非 127.x.x)
遍历所有网络接口,过滤掉回环、链路本地、未启用和虚拟网卡,只保留有效的 IPv4 地址:
调用
获取全部网卡
对每个接口,用
获取地址列表
逐个检查:
、
、
必须全为 false;且
跳过常见虚拟网卡名,如
、
、
开头的接口
若有多块有效网卡(如 WiFi + 有线),建议按路由表逻辑选默认出口网卡,而非固定取第一个
获取可靠主机名(绕过 DNS 反查)
不要依赖
的结果,它会尝试把当前主机名再做一次 DNS 查询,失败就 fallback 到
:
Linux/macOS 下执行
,读取标准输出
Windows 下用
备用方案:读环境变量
(Linux/macOS)或
(Windows)
避免使用
——这是登录用户名,不是主机名
域名解析要注意的三个坑
表面简单,实则暗含超时、缓存与协议优先级问题:
DNS 缓存不可控:JVM 默认缓存成功解析(永久)和失败解析(10 秒),可通过系统属性调整:
IPv6 优先导致卡顿:若 DNS 返回 AAAA 记录但本地 IPv6 不通,方法可能阻塞约 30 秒;可临时禁用 IPv6:
仅返回首个地址:
只取第一个 A 或 AAAA 记录;如需全部结果(比如负载均衡场景),改用
外网 IP 不能靠 InetAddress
类完全无法获取机器对外的真实公网 IP,因为它只处理本机网络栈配置,不发起外部请求:
所有本地方法(
、
)最多返回内网地址(如
、
)
要获取公网出口 IP,必须调用可信 HTTP 接口,例如:
(纯文本返回 IP)或
(JSON)
注意添加超时和重试机制,这类服务虽稳定但并非 Java 标准库能力
InetAddress.getLocalHost()127.0.0.1UnknownHostExceptionNetworkInterface.getNetworkInterfaces()interface.getInetAddresses()addr.isLoopbackAddress()addr.isLinkLocalAddress()!addr.isAnyLocalAddress()addr instanceof Inet4Address"docker0""vboxnet""br-"InetAddress.getHostName()localhostRuntime.getRuntime().exec("hostname")Runtime.getRuntime().exec("cmd /c hostname")System.getenv("HOSTNAME")System.getenv("COMPUTERNAME")System.getProperty("user.name")InetAddress.getByName()-Dsun.net.inetaddr.ttl=30-Djava.net.preferIPv4Stack=truegetByName()getAllByName()InetAddressgetLocalHostgetByName("myhost")192.168.x.x10.x.x.xhttps://api.ipify.orghttps://httpbin.org/ip