1. 简介
java.net.InetAddress类是Java对Ip地址的高层表示。大多数其他网络都要用到这个类,包括Socket、ServerSocket、URL、DatagramSocket、DatagramPacket等。一般来讲,它包括一个主机名和一个IP地址。它提供了获取和操作 IP 地址的方法,可以用于网络编程、服务器配置、主机管理等场景。InetAddress类的常用方法和功能包括:
- 获取 IP 地址:
getByName(String host)
:通过主机名或 IP 地址字符串获取一个 InetAddress 对象。
getLocalHost()
:获取本地主机的 InetAddress 对象。
- 获取主机名和 IP 地址信息:
getHostName()
:获取主机的主机名。
getHostAddress()
:获取主机的 IP 地址字符串。
- 检查 IP 地址类型:
isLoopbackAddress()
:检查是否为回环地址(Loopback Address)。
isMulticastAddress()
:检查是否为组播地址(Multicast Address)。
isAnyLocalAddress()
:检查是否为通配地址(Any Local Address)。
- 进行 IP 地址的比较和判断:
equals(Object obj)
:比较两个 InetAddress 对象是否相等。
hashCode()
:获取 IP 地址的哈希码值。
- 获取与 IP 地址相关的其他信息:
getCanonicalHostName()
:获取规范的主机名。
getAddress()
:获取原始的 IP 地址字节数组。
toString()
:返回 IP 地址的字符串表示。
InetAddress类可以用于解析域名、获取主机的 IP 地址、判断 IP 地址的类型等操作。它是进行网络编程和系统配置的基础类之一。
2. 创建新的InetAddress对象
InetAddress类没有公共构造函数。实际上,InetAddress有一些静态工厂方法,可以连接到DNS服务器来解析主机名。最常用的是InetAddress.getByName
public class QuizCardBuilder {
public static void main(String[] args) throws UnknownHostException {
InetAddress address=InetAddress.getByName("www.baidu.com");
System.out.println(address);
}
}
InetAddress address=InetAddress.getByName("www.baidu.com");
该方法会建立一个与本地DNS服务器的一个连接,来查找名字和数字地址(如果你之前查找过这个主机,这个信息可以在本地缓存,如果是这样,就不用建立网络连接了)。如果DNS服务器找不到这个地址,则会抛出UnknownHostException
异常。
getByName方法可以提供一个IP地址作为参数,会为所请求的IP地址创建一个InetAddress对象,但不会检查DNS,即它可能会为一个实际不存在的也无法连接的主机创建InetAddress对象,而只有显示的调用getHostName时才会完成真正的DNS查找,但如果没找到的话,也不会抛出
UnKnownHostException
异常,而是主机名继续保持原来的IP地址字符串
- getLocalHost()方法,会为运行这个代码的主机返回一个InetAddress对象
public class QuizCardBuilder {
public static void main(String[] args) throws UnknownHostException {
InetAddress address=InetAddress.getLocalHost();
System.out.println(address);
}
}
3. 缓存
由于DNS查找的开销可能相当大,所以InetAddress会缓存查找到的结果。一旦得到一个给定主机的地址,就不会再次查找地址。只要在程序运行期间IP地址没有改变,这就没有问题。这种方式的负面结果就是,有可能刚开始尝试解析一个主机失败,但随后再次尝试时会成功。因为从远程DNS服务器发来的信息孩子传输中,第一次尝试超时,然后这个地址到达本地DNS,所以下一次请求时可用。出于这个原因,Java对于不成功的DNS查询只缓存10s。其实这个时间可以通过系统属性来控制,networkaddress.cache.ttl
和networkaddress.cache.negative.ttl
。其中第一个属性指定了成功的DNS查找结果缓存的时间,单位为s,后面一个属性指定了不成功的查找结果缓存的时间,单位为s。
4. 安全性问题
从主机名创建一个新的InetAddress对象被认为是一个潜在的不安全操作,因为这需要一个DNS查找。在默认的安全管理器控制下的不可信applet(一种可以嵌入到网页中的java程序)只允许获得它的初始主机的IP地址,这可能是本地主机。不允许不可信代码(指的是那些不受信任或来源不可靠的代码。不可信代码可能是来自第三方或外部系统的代码,或者是用户输入的代码。这些代码的执行可能具有潜在的安全风险或不可预测的行为)由任何其它主机创建InetAddress对象,不可信代码可以由字符串形式的IP地址构造InetAddress对象,但不会为这样的地址完成DNS查找。由于禁止与初始主机之外的主机建立网络连接,不可信的代码不允许对第三方的主机完成任意的DNS查找,任务的DNS查找会打开一个隐藏的通道,通过它,程序可以和第三方主机对话。由于任意DNS查找会泄露信息,所以要禁止任意的DNS查找。
不可信代码允许调用getLocalHost(),不过在这种环境下,getLocalHost()总是返回主机名localhost/127.0.0.1。禁止applet找出真正的主机名和地址的原因在于,运行applet的计算机可能故意隐藏在防火墙后面,在这种情况下,applet不应该作为通道来获取web服务器还没有的信息。但与所有的安全性检查一样,禁止DNS解析可以对可信代码放宽要求,要测试一个主机能否解析可以调用checkConnect方法:
public void checkConnect(String hostname,int port)
当port参数为1时,这个方法检查能否调用DNS解析指定的hostname(如果大于-1,这个方法检查是否运行在指定端口对指定主机建立连接)
5. 获取方法
InetAddress保护4个获取方法,可以将主机名作为字符串返回,将IP地址返回为字符串和字节数组:
public String getHostname()
public String getCanonicaHostName()
public byte[] getAddress()
public String getHostAddress()
没有对应的setHostname()和setAddress()方法,这说明java.net之外的包无法在后台改变InetAddress对象的字段,所以它是线程安全的
- getHostname
该方法返回一个String对象,其中保护主机名字,以及这个InetAddress对象表示的IP地址。如果这台机器没有主机名或者安全管理器阻止确定主机名,就会返回分四段格式的IP地址。
- getCanonicaHostName
该方法和getHostname方法类似,不过在与DNS联系方面更加积极,getHostName只是在不知道主机名时才会联系DNS,而该方法即使知道也会联系DNS,可能会替换原来缓存的主机名。
public class QuizCardBuilder {
public static void main(String[] args) throws UnknownHostException {
InetAddress address=InetAddress.getByName("www.baidu.com");
System.out.println(address.getCanonicalHostName());
System.out.println(address.getHostName());
}
}
6. 地址类型
有些IP地址和地址模式有特殊的含义。例如127.0.0.1时本地回送地址。224.0.0.0到239.255.255.255范围内的IPv4组播地址,可以同时发送到多个订阅的主机,java提供了10个方法来测试InetAddress对象是否符合其中某个标准:
public boolean isAnyLocalAddress() //检查是不是通配地址(匹配本地的任何地址)
public boolean isLoopbackAddress() //检查是不是回送地址(回送地址直接在IP层连接一台计算机)
public boolean isLinkLocalAddress() //检查是不是iPv6本地链接地址
public boolean isSiteLocalAddress() //检查是不是一个ipv6本地网站地址
public boolean isMulticastAddress() //检查是不是一个组播地址
public boolean isMCGlocal() //检查是不是一个全球组播地址
public boolean isMCNodeLocal() //检查是不是一个本地接口组播地址
public boolean isMCSiteLocal() //检查是不是网站范围组播地址
public boolean isMCOrgLocal() //检查是不是一个组织范围组播地址
public boolean isLinkLocal() //检查是不是一个字网范围组播地址
7. 测试可达性
InetAddress类有两个isReachable方法,可以测试一个特定的节点对当前主机是否可达,连接可能因为很多原因而阻塞,包括防火墙、代理服务器、行为失常的路由器和断开线缆等,或者只是因为试图连接时远程主机没有开机
public boolean isReachable(int timeout) throw IOException
public boolean isReachable(NetworkInterface interface,int ttl, int timeout)
这些方法尝试使用traceroute(更确切的说,就是ICMP echo请求)查看指定地址是否可达,如果主机在timeout时间内没有反应,则方法返回true,否则返回false。如果网络出现错误,则抛出IOException。第二个方法还允许指定从哪个本地网络接口建立连接,以及生成时间(连接被丢弃前尝试的最大网络跳数)
public class QuizCardBuilder {
public static void main(String[] args) {
try {
// 使用默认超时时间的 isReachable 方法
boolean isReachable = InetAddress.getByName("www.baidu.com").isReachable(5000);
System.out.println("Default Timeout - Is host reachable? " + isReachable);
// 使用指定网络接口、生存时间和超时时间的 isReachable 方法
NetworkInterface networkInterface = NetworkInterface.getByName("eth0");
boolean isReachableWithInterface = InetAddress.getByName("www.baidu.com")
.isReachable(networkInterface, 128, 5000);
System.out.println("With Network Interface - Is host reachable? " + isReachableWithInterface);
} catch (IOException e) {
e.printStackTrace();
}
}
}
8. Object方法
java.net.InetAddress继承自java.lang.Object。因此,它可以访问Object类的所有方法。
- equals():当两个InetAddress对象具有相同的IP地址时相等,并不要求拥有相同的主机名
- hashcode():该方法返回int只根据IP地址来计算,它不考虑主机名
- toString():可依返回对象的简单文字表示