前言
本文接着上文的内容,主要解答上文留下的疑问:既然不能使用InetAddress#getLocalHost()直接去获取到本机的IP地址,那么如何破呢?
本文将介绍的是一种通用的获取本机IP地址的解决方案,也就是所谓的“正确姿势”。
正文
为了更好的解释为何InetAddress#getLocalHost()不靠谱,有必要先普及下Linux下的相关文件的解释,比较我们的Java应用绝大部分情况下都是跑在Linux环境下的(甚至国内基本都跑在centos上吧)。
Linux下/sysconfig/network、hosts、host.conf、resolv.conf文件解释
这几个文件都位于/etc/目录下,下面分别给出解释和示例:
- /sysconfig/network:此文件是针对本计算机的,是给计算机起的一个名字,是计算机的一个标识。可以使用uname -n 命令来查看本地计算机的计算机名称(比如本例我使用该命令得到的值是l-xxx.syc.prod.ali.qr,也就是配置里的HOSTNAME的值)
# 支持网络通信 NETWORKING=yes # 主机名,若你不设置默认是localhost.localdomain # 使用hostname命令查看到的就是这个值 HOSTNAME=l-xxx.syc.prod.ali.qr # 不启用IPV6的支持 NETWORKING_IPV6=no PEERNTP=no
hosts
:不同于network,此文间是在网络上使用的。和Windows系统下的hosts文件相类似,就是一个文本文件,里面存放一些IP和域名的对应关系(注意:都是先ip,后域名)
127.0.0.1 localhost # ::1表示的时ipv6的本地地址,也就是0000:0000:0000:0000:0000:0000:0000:0001 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 # 内网ip地址 -> 主机名 的映射关系 10.102.1.153 l-xxx.syc.prod.ali.qr
host.conf
:解析顺序/方式,属于一种规则配置。
# 这里规定先使用DNS来解析域名,然后再查询“/etc/hosts”文件(也可以相反,你调个顺序即可) order bind,hosts # 指定是否“/etc/hosts”文件中指定的主机可以有多个地址 multi on
- resolv.conf:DNS服务器的配置文件,用于设置DNS服务器的IP地址及DNS域名,还包含了主机的域名搜索顺序。该文件由域名解析器来读取(下面会有Java代码示例)
- 格式:每行以一个关键字开头,后接一个或多个由空格隔开的参数
- 可选的关键字有:
- nameserver:(最重要,此关键字必选,其它可选)定义DNS服务器的IP地址,可以有很多行的nameserver,每一个带一个IP地址。在查询时就按nameserver在本文件中的顺序进行,且只有当第一个nameserver没有反应时才查询下面的nameserver。
- domain:定义本地域名/主机的域名
- search:定义域名的搜索列表
- search和domain不能共存,如果同时存在,以最后出现的为准。
- sortlist:对返回的域名进行排序,如sortlist 130.155.160.0/255.255.240.0 130.155.0.0
- options:用于配置resolver的内置变量,不是resolv.conf的常见配置。语法如下:options [option] ...
- ndots:[n]:设置调用res_query()解析域名时域名至少包含的点的数量
- timeout:[n]:设置等待dns服务器返回的超时时间,单位秒。默认值5
- attempts:[n]:设置resolver向DNS服务器发起域名解析的请求次数。默认值2
- …
# 一般是内网DNS服务器地址,这样就可以解析你的内网域名了喽 nameserver 202.102.192.68 nameserver 202.102.192.69 search qq.com baidu.com options no-check-names options attempts:1 options timeout:1
了解了这些概念后,接下来就得认识InetAddress这个API了。本文将会演示它在windows上(本机)以及Linux下运行的案例,会有差异,请注意区分。
直接使用getLocalHost()获取本机IP的错误示例
标题已经很明显指出了:这是错误示例。我相信绝大部分小伙伴获取本机IP都后悔这么用:
public static void main(String[] args) throws UnknownHostException { InetAddress localHost = InetAddress.getLocalHost(); System.out.println(localHost.getHostAddress()); }
运行程序,在不同的操作系统上值可能还不一样:
- 在windows上:192.168.199.175
- 在windows上看似正常。但是但是但是,请你开一个vpn再运行试一下,定会让你大跌眼镜(比如我开启公司的vpn后,输出的值是2.0.0.137)
- 可以看到当出现多个网卡接口工作时,windows可能就不好使了,而多个网卡同时工作的情况是很正常的(比较虚拟网卡经常很多)
- 在Linux上:127.0.0.1
- what?
为何在Linux下请你一定不要使用它来获取本机IP,因为它就是简单的读取/etc/hosts的内容,所以它默认返回的是127.0.0.1非常的不靠谱,因此本方法十分不建议在生产上使用。
/etc/hosts的第一行一般均是:127.0.0.1 localhost,所以返回值是127.0.0.1(倘若你把第一行改为127.1.1.1 localhost,那么它的返回值就是127.1.1.1了)
获取本机IP地址的正确姿势
关于获取本机地址的正确姿势,主要分为如下两种场景展开说明。
简单情况(废弃)
简单情况下,就可以通过InetAddress.getLocalHost()来获取到本机ip地址。注意这里的关键词:简单。因此它对环境是有要求的:
- windows环境
- 非多网卡协同工作环境(比如不能开启vpn)
很明显,这种“简单”情况在实际生产中并不存在,因此仅限yy,不可使用。