InetAddress 与网络地址 | JavaSE
InetAddress 与网络地址
一、学习目标
学完本章,你应该能够:
- 能够解释
InetAddress类在 Java 网络编程中的作用。 - 能够使用
InetAddress.getLocalHost()获取本地主机地址对象。 - 能够使用
InetAddress.getByName()根据域名或 IP 字符串获取网络地址对象。 - 能够使用
getHostName()和getHostAddress()获取主机名及文本形式 IP 地址。 - 能够使用
getLoopbackAddress()正确获取回环地址。 - 能够理解域名解析可能返回多个 IP 地址,并使用
getAllByName()获取它们。 - 能够正确理解
isReachable()的能力边界,而不是把它简单等同于ping。
二、核心知识
2.1 InetAddress 是什么
Java 在:
java.net
包中提供了:
InetAddress
用于表示 Internet Protocol 地址相关信息。
导包:
import java.net.InetAddress;
可以把 InetAddress 理解为:
Java 对“主机名 + IP 地址”这类网络地址信息进行面向对象封装后的核心类型之一。
例如:
www.example.com
↓
InetAddress
↓
93.xxx.xxx.xxx
或者:
当前计算机
↓
InetAddress
↓
主机名 + IP 地址
2.2 InetAddress 不是 Socket
这是一个非常重要的边界。
InetAddress:
表示网络地址信息
而 Socket:
表示网络通信端点/连接相关能力
本章我们只是解决:
“目标在哪?”
后面学习 UDP、TCP 时才真正解决:
“怎么把数据发过去?”
知识顺序:
InetAddress
↓
得到目标地址
↓
DatagramSocket / Socket
↓
真正发送和接收数据
2.3 InetAddress 的创建方式
InetAddress 通常不是通过:
new InetAddress()
创建。
而是通过静态工厂方法获得对象。
常用方法:
| 方法 | 作用 |
| --------------------------------------- | ------------------------------------ |
| InetAddress.getLocalHost() | 获取本地主机地址对象 |
| InetAddress.getByName(String host) | 根据主机名、域名或 IP 字符串解析地址 |
| InetAddress.getAllByName(String host) | 获取某主机名对应的全部已解析 IP |
| InetAddress.getLoopbackAddress() | 获取回环地址 |
2.4 获取本地主机地址
最基础的写法:
InetAddress localHost = InetAddress.getLocalHost();
完整示例:
import java.net.InetAddress;
public class InetAddressDemo01 {
public static void main(String[] args) throws Exception {
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
}
}
需要注意:
getLocalHost()
不是简单写死返回:
127.0.0.1
它会根据当前操作系统主机配置获取本地主机名,并尝试解析得到对应地址。
因此不同电脑输出可能完全不同。
2.5 获取主机名
可以使用:
getHostName()
例如:
InetAddress localHost = InetAddress.getLocalHost();
String hostName = localHost.getHostName();
System.out.println(hostName);
可能输出:
LingXi-PC
具体值由当前操作系统与网络配置决定。
2.6 获取 IP 地址字符串
使用:
getHostAddress()
例如:
InetAddress localHost = InetAddress.getLocalHost();
String address = localHost.getHostAddress();
System.out.println(address);
可能输出:
192.168.1.23
也可能是 IPv6 地址。
因此不要在代码中假定:
getHostAddress()
一定返回 IPv4
2.7 根据域名获取 InetAddress
可以使用:
InetAddress.getByName(...)
例如:
InetAddress address =
InetAddress.getByName("www.example.com");
完整示例:
import java.net.InetAddress;
public class InetAddressDemo02 {
public static void main(String[] args) throws Exception {
InetAddress address =
InetAddress.getByName("www.example.com");
System.out.println("主机名:" + address.getHostName());
System.out.println("IP地址:" + address.getHostAddress());
}
}
这里发生了一个非常关键的过程:
www.example.com
↓
系统配置的名称解析机制
↓
IP 地址
↓
InetAddress
通常会涉及 DNS。
2.8 getByName 也可以接收 IP 字符串
例如:
InetAddress address =
InetAddress.getByName("127.0.0.1");
甚至可以直接传一个合法的 IPv6 地址文本。
所以:
getByName(String host)
中的 host 并不仅仅表示“域名”。
它可以是:
主机名
域名
IP 地址文本
2.9 获取回环地址
如果真正想表示:
当前主机自身的回环接口
Java 提供了更明确的方法:
InetAddress.getLoopbackAddress()
例如:
import java.net.InetAddress;
public class InetAddressDemo03 {
public static void main(String[] args) {
InetAddress loopback =
InetAddress.getLoopbackAddress();
System.out.println(loopback.getHostAddress());
}
}
返回的可能是:
127.0.0.1
也可能是 IPv6:
::1
具体取决于运行环境。
所以:
getLocalHost()
和:
getLoopbackAddress()
不要混为一谈。
2.10 一个域名可能对应多个 IP
大型网站通常不会只有一台服务器。
例如:
www.example.com
理论上可能解析出:
IP1
IP2
IP3
...
Java 提供:
InetAddress.getAllByName(host)
获取全部解析结果。
例如:
import java.net.InetAddress;
public class InetAddressDemo04 {
public static void main(String[] args) throws Exception {
InetAddress[] addresses =
InetAddress.getAllByName("www.example.com");
for (InetAddress address : addresses) {
System.out.println(address.getHostAddress());
}
}
}
这段代码说明:
域名
≠
永远对应唯一 IP
2.11 UnknownHostException
如果 Java 无法确定目标主机地址,可能抛出:
UnknownHostException
它位于:
java.net
包中。
例如:
InetAddress.getByName("this-host-does-not-exist.invalid");
可能解析失败。
于是:
域名
↓
名称解析失败
↓
UnknownHostException
因此真实开发中需要考虑:
- 域名输入错误
- DNS 故障
- 当前没有网络
- 名称解析配置异常
而不能认为:
getByName()
永远成功。
三、使用方法
3.1 获取本地主机名和 IP
完整示例:
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressLocalDemo {
public static void main(String[] args) {
try {
InetAddress localHost =
InetAddress.getLocalHost();
System.out.println(
"主机名:" + localHost.getHostName()
);
System.out.println(
"IP地址:" + localHost.getHostAddress()
);
} catch (UnknownHostException e) {
System.out.println("无法解析本地主机地址");
e.printStackTrace();
}
}
}
执行逻辑:
getLocalHost()
↓
获得 InetAddress
↓
getHostName()
↓
获取主机名
getHostAddress()
↓
获取 IP 文本
3.2 获取远程主机地址
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressRemoteDemo {
public static void main(String[] args) {
try {
InetAddress remote =
InetAddress.getByName("www.example.com");
System.out.println(
"主机名:" + remote.getHostName()
);
System.out.println(
"IP地址:" + remote.getHostAddress()
);
} catch (UnknownHostException e) {
System.out.println("无法解析目标主机");
}
}
}
这里的核心代码其实只有:
InetAddress remote =
InetAddress.getByName("www.example.com");
之后就可以从对象中读取地址信息。
3.3 获取所有解析地址
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressAllDemo {
public static void main(String[] args) {
try {
InetAddress[] addresses =
InetAddress.getAllByName("www.example.com");
for (InetAddress address : addresses) {
System.out.println(
address.getHostAddress()
);
}
} catch (UnknownHostException e) {
System.out.println("域名解析失败");
}
}
}
这里再次出现之前学习过的:
数组
增强 for
异常处理
JavaSE 的知识已经开始组合使用。
3.4 判断是否可能到达目标主机
InetAddress 提供:
boolean isReachable(int timeout)
例如:
import java.net.InetAddress;
public class InetAddressReachableDemo {
public static void main(String[] args) throws Exception {
InetAddress address =
InetAddress.getByName("www.example.com");
boolean reachable =
address.isReachable(3000);
System.out.println(reachable);
}
}
参数:
3000
单位是:
毫秒
也就是最多尝试:
3 秒
3.5 非常重要:isReachable 不等于 ping
很多初学代码会写:
System.out.println(address.isReachable(5000));
然后解释成:
“这就是 Java 在执行 ping。”
这种理解不够准确。
isReachable() 是一个:
best effort(尽力而为)的可达性测试。
Java 实现可能:
- 尝试 ICMP Echo
- 在权限不足等情况下采用其他方式
而:
- 防火墙
- 系统安全策略
- 目标服务器配置
都可能影响结果。
所以:
isReachable(...) == false
不能严格推出:
目标服务器所有服务都无法访问
例如完全可能:
isReachable() → false
但是:
HTTPS 443 → 可以正常访问
因此实际网络诊断不能只依赖这一方法。
3.6 InetAddress 基础综合案例
import java.net.InetAddress;
public class InetAddressDemo {
public static void main(String[] args) throws Exception {
// 1. 获取本地主机地址
InetAddress localHost =
InetAddress.getLocalHost();
System.out.println("=== 本地主机 ===");
System.out.println(
"主机名:" + localHost.getHostName()
);
System.out.println(
"IP地址:" + localHost.getHostAddress()
);
// 2. 获取回环地址
InetAddress loopback =
InetAddress.getLoopbackAddress();
System.out.println("=== 回环地址 ===");
System.out.println(
loopback.getHostAddress()
);
// 3. 解析远程主机
InetAddress remote =
InetAddress.getByName("www.example.com");
System.out.println("=== 远程主机 ===");
System.out.println(
"主机名:" + remote.getHostName()
);
System.out.println(
"IP地址:" + remote.getHostAddress()
);
// 4. 可达性尝试
boolean reachable =
remote.isReachable(3000);
System.out.println(
"可达性测试:" + reachable
);
}
}
这段代码已经覆盖本章最核心的 API。
四、原理与进阶
4.1 getLocalHost 到底做了什么
getLocalHost() 的含义不是:
永远返回 127.0.0.1
而是大致经历:
操作系统本地主机名
↓
名称解析
↓
InetAddress
因此电脑网络配置不同:
getLocalHost()
得到的结果也可能不同。
这也是为什么:
同一段 Java 程序
在不同机器上可能打印:
192.168.x.x
或者其他地址。
4.2 getHostName 可能涉及名称解析
对于:
getHostName()
不能简单理解为:
从对象内部读取一个永远现成的字符串
如果 InetAddress 对象创建时没有保存主机名,系统可能尝试进行:
反向名称解析
IP → Host Name
因此网络 API 中一些看似普通的方法,也可能依赖系统名称解析环境。
4.3 getHostAddress 更适合直接获取 IP 文本
如果你的真正需求只是:
我要把 IP 地址打印出来。
优先使用:
getHostAddress()
例如:
System.out.println(address.getHostAddress());
它表达的语义非常明确:
InetAddress
↓
IP 地址文本
4.4 Inet4Address 与 Inet6Address
InetAddress 是网络地址类体系中的基础类型。
Java 还提供:
Inet4Address
Inet6Address
分别用于:
IPv4
IPv6
因此:
InetAddress
并不意味着只能表示 IPv4。
例如:
InetAddress address =
InetAddress.getByName("...");
最终返回的真实对象可能是:
Inet4Address
也可能是:
Inet6Address
这也是面向对象中:
父类引用
指向子类对象
思想在 Java 核心 API 中的真实应用。
4.5 DNS 与 Java 网络 API 的关系
当执行:
InetAddress.getByName("www.example.com");
时,可以简单理解为:
Java
↓
操作系统配置的名称解析机制
↓
DNS 等名称服务
↓
目标 IP
↓
InetAddress
Java 并不是凭空知道:
www.example.com
的 IP 地址。
背后仍然离不开网络名称解析体系。
五、实践应用
5.1 Socket 连接之前解析服务器地址
后续可能写:
Socket socket =
new Socket("example.com", 9999);
其中域名最终仍然需要解析成 IP。
因此:
InetAddress
是理解 Socket 网络寻址的重要基础。
5.2 获取客户端 IP
后续服务器接受客户端连接后,经常会看到:
socket.getInetAddress()
最终获得的就是:
InetAddress
对象。
然后:
socket.getInetAddress()
.getHostAddress()
就能获得客户端 IP。
例如服务器日志可能输出:
客户端上线:192.168.1.20
所以本章并不是一个孤立 API。
后续几乎整个网络编程阶段都会不断遇到:
InetAddress
5.3 局域网聊天程序
未来开发:
局域网即时通信系统
时,服务端需要识别:
客户端来自哪个 IP
例如:
Client A
192.168.1.20
↓
Client B
192.168.1.21
↓
Server
192.168.1.100:9999
服务器可以通过 Socket 获取:
InetAddress
进一步获得客户端地址信息。
六、常见问题
6.1 InetAddress 可以 new 吗?
通常不会直接:
new InetAddress()
而是通过静态方法获取,例如:
InetAddress.getLocalHost();
InetAddress.getByName(...);
InetAddress.getLoopbackAddress();
6.2 getLocalHost 就是获取 127.0.0.1 吗?
不是。
如果需要明确获取回环地址,应理解:
InetAddress.getLoopbackAddress()
而:
getLocalHost()
会基于系统本地主机名及其解析结果获得地址。
6.3 getByName 一定访问互联网吗?
不一定。
例如:
InetAddress.getByName("127.0.0.1");
传入的就是 IP 文本。
而:
InetAddress.getByName("localhost");
也可能直接由本地 hosts 或系统名称解析机制处理。
只有需要解析远程域名时,才可能涉及外部 DNS 查询。
6.4 域名一定只对应一个 IP 吗?
不是。
因此 Java 提供:
getAllByName(...)
用于获取多个解析结果。
6.5 isReachable 返回 false 就说明网站挂了吗?
不能。
它只能说明:
当前 Java 可达性测试没有成功确认该主机可达。
可能原因包括:
- 防火墙禁止 ICMP
- 权限限制
- 网络策略
- 超时
- 目标配置
网站具体端口仍可能正常工作。
6.6 为什么 getByName 会抛 UnknownHostException?
因为 Java 可能无法确定目标主机的 IP 地址。
典型原因:
域名不存在
DNS 失败
名称配置错误
网络异常
所以网络程序天然需要处理失败场景。
6.7 为什么我的运行结果和教程不同?
网络程序与普通:
int a = 10;
不同。
结果受到运行环境影响,例如:
- 电脑主机名
- Windows / Linux
- Wi-Fi 网络
- DNS
- IPv4 / IPv6 配置
- VPN
- 防火墙
- 当前网络是否连接
因此网络编程中:
结果不完全一致
是正常现象。
更重要的是理解 API 的语义。
七、练习与验收
7.1 知识问答
InetAddress位于哪个包?InetAddress主要表示什么?getLocalHost()有什么作用?getLoopbackAddress()与getLocalHost()有什么区别?getByName()参数可以是什么?getHostName()与getHostAddress()分别返回什么?- 为什么同一个域名可能对应多个 IP?
getAllByName()解决什么问题?UnknownHostException通常在什么情况下出现?- 为什么不能将
isReachable()简单理解为系统ping?
7.2 代码阅读
阅读:
InetAddress address =
InetAddress.getByName("www.example.com");
System.out.println(address.getHostName());
System.out.println(address.getHostAddress());
回答:
- 第一行代码主要进行了什么操作?
address保存的是字符串还是对象?getHostName()返回什么信息?getHostAddress()返回什么信息?- 如果域名无法解析,可能出现什么异常?
7.3 手写代码
关闭 AI 自动补全,从零实现:
InetAddressDemo1
要求:
- 获取本地主机
InetAddress。 - 打印本地主机名。
- 打印本地主机 IP。
- 获取回环地址。
- 根据一个域名获取远程主机对象。
- 打印远程 IP。
- 使用
isReachable(3000)进行一次可达性尝试。
7.4 Debug
下面代码存在概念错误:
InetAddress ip = InetAddress.getLocalHost();
System.out.println(
"我的回环地址:" + ip.getHostAddress()
);
问题:
getLocalHost()得到的地址为什么不能直接称为回环地址?
请修改程序,使其真正获取:
Loopback Address
再观察:
InetAddress ip =
InetAddress.getByName("abc.this-domain-does-not-exist.invalid");
System.out.println(ip.getHostAddress());
回答:
- 这段代码可能发生什么?
- 属于编译期错误还是运行期异常?
- 应该如何处理?
7.5 综合训练
编写:
NetworkAddressInspector
要求用户给程序一个:
域名 / 主机名 / IP 字符串
程序完成:
输入目标
↓
getAllByName()
↓
得到 InetAddress[]
↓
逐个打印 IP
↓
对每个地址尝试 isReachable()
输出格式自行设计。
暂时不要求真正建立 TCP 或 UDP 通信。
7.6 本章验收
如果关闭资料后,你能够从零写出:
InetAddress.getLocalHost();
InetAddress.getLoopbackAddress();
InetAddress.getByName(...);
InetAddress.getAllByName(...);
address.getHostName();
address.getHostAddress();
address.isReachable(...);
并且能够解释:
域名
↓
名称解析
↓
IP 地址
↓
InetAddress
同时知道:
InetAddress 只是在解决地址问题
Socket 才开始解决真正的数据通信问题
那么本章已经达到学习要求。
最终知识链:
InetAddress
│
┌──────────┼──────────┐
│ │ │
LocalHost Loopback Remote Host
│ │ │
└──────────┼──────────┘
│
HostName / IP
│
▼
Socket 编程