Java中InetAddress的使用(二):获取本机IP地址的正确姿势【享学Java】(上)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
云解析DNS,个人版 1个月
简介: Java中InetAddress的使用(二):获取本机IP地址的正确姿势【享学Java】(上)

前言


本文接着上文的内容,主要解答上文留下的疑问:既然不能使用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地址。注意这里的关键词:简单。因此它对环境是有要求的:


  1. windows环境
  2. 非多网卡协同工作环境(比如不能开启vpn)


很明显,这种“简单”情况在实际生产中并不存在,因此仅限yy,不可使用。


相关文章
|
13天前
|
网络协议 安全 Java
Java网络编程入门涉及TCP/IP协议理解与Socket通信。
【6月更文挑战第21天】Java网络编程入门涉及TCP/IP协议理解与Socket通信。TCP/IP协议包括应用层、传输层、网络层和数据链路层。使用Java的`ServerSocket`和`Socket`类,服务器监听端口,接受客户端连接,而客户端连接指定服务器并交换数据。基础示例展示如何创建服务器和发送消息。进阶可涉及多线程、NIO和安全传输。学习这些基础知识能助你构建网络应用。
22 1
|
2月前
|
网络协议 Java
Java的Socket编程:TCP/IP与UDP深入探索
Java的Socket编程:TCP/IP与UDP深入探索
25 0
|
11天前
|
网络协议 Java 程序员
TCP/IP协议栈是网络通信基础,Java的`java.net`包提供工具,使开发者能利用TCP/IP创建网络应用
【6月更文挑战第23天】 **TCP/IP协议栈是网络通信基础,它包含应用层(HTTP, FTP等)、传输层(TCP, UDP)、网络层(IP)、数据链路层(帧, MAC地址)和物理层(硬件信号)。Java的`java.net`包提供工具,使开发者能利用TCP/IP创建网络应用,如Socket和ServerSocket用于客户端和服务器通信。**
24 3
|
1月前
|
Java Apache Maven
蓝易云 - java判断ip是否为指定网段
在这个例子中,我们首先创建了一个 `SubnetUtils`对象,它表示一个子网。然后,我们使用 `isInRange`方法来检查指定的IP地址是否在这个子网内。如果IP地址在子网内,`isInRange`方法将返回 `true`,否则返回 `false`。
44 3
|
29天前
|
数据采集 Java 数据安全/隐私保护
使用Java进行网络采集:代理IP与参数传递详解
Java参数传递是按值传递,包括对象引用的值。当传递对象时,方法内部修改对象内容会影响原始对象,但不能改变原始引用。示例展示了如何在爬虫代理中使用此机制,通过`ProxySettings`类传递代理信息,方法内可访问但不能更改原始对象。理解这一机制对编写高效无错的Java代码至关重要。
使用Java进行网络采集:代理IP与参数传递详解
|
2月前
|
Java 程序员 API
全民上手大模型--ollama+langchain+通义千问零费用java+python跑通本机大模型
全民上手大模型--ollama+langchain+通义千问零费用java+python跑通本机大模型
411 0
|
2月前
|
存储 Java 编译器
Java | 如何从内存解析的角度理解“数组名实质是一个地址”?
这篇文章讨论了Java内存的简化结构以及如何解析一维和二维数组的内存分配。在Java中,内存分为栈和堆,栈存储局部变量,堆存储通过`new`关键字创建的对象和数组。方法区包含静态域和常量池。文章通过示例代码解释了一维数组的创建过程,分为声明数组、分配空间和赋值三个步骤,并提供了内存解析图。接着,介绍了二维数组的内存解析,强调二维数组是“数组的数组”,其内存结构中,外层元素存储内层数组的地址。最后,文章提到了默认初始化方式对初始值的影响,并给出了相关测试代码。
29 0
|
2月前
|
存储 Java 定位技术
【Java】根据IP地址获取省市
【Java】根据IP地址获取省市
166 1
|
1天前
|
Java 调度
Java中的线程池机制详解
Java中的线程池机制详解