赞
踩
绝大部分知识与实例来自O’REILLY的《Java网络编程》(Java Network Programming,Fourth Edition,by Elliotte Rusty Harold(O’REILLY))。
InetAddress类位于java.net包中,是Java对IP地址(包括IPv4和IPv6)的高层表示。许多其他网络相关类,包括Socket、ServerSocket、URL等都用到了这个类。这个类的每个实例包含一个IP地址(IP address)以及这个IP地址对应的主机名(host name)。
InetAddress类没有public的构造器,想要获取它的实例,需要通过它的一些静态工厂方法。最常用的一个是InetAddress.getByName(),能够根据域名或者IP地址获取InetAddress实例。这个方法会建立与本地DNS服务器的一个连接,并查找主机名和IP地址。如果DNS找不到这个地址,方法会抛出一个UnknownHostException,IOException的一个子类。
public static void ShowAddress(String domainName){
InetAddress address;
try {
address = InetAddress.getByName(domainName);
System.out.println(address);
} catch (UnknownHostException e) {
System.out.println("Could not find" + domainName);
e.printStackTrace();
}
}
public static void main(String[] args) {
ShowAddress("www.baidu.com");
}
输出:
www.baidu.com/183.232.231.172
另外一个经常使用的是InetAddress.getLocalHost,用于返回运行代码的主机对应的InetAddress对象。
public static void ShowLocalAddress(){
try {
InetAddress address = InetAddress.getLocalHost();
System.out.println(address);
} catch (UnknownHostException e) {
System.out.println("Could not find this computer's address.");
}
}
public static void main(String[] args) {
ShowLocalAddress();
}
另外,有时一个主机名可能有多个地址,如果想要全部获得,可以使用getAllByName()方法。该方法会返回一个InetAddress数组。
最后的两个构造器,用于根据原始IP地址和主机名构建一个InetAddress对象:
public static InetAddress getByAddress(byte[] addr) throws UnknownHostException
public static InetAddress getByAddress(String hostName,byte[] addr) throws UnknownHostException
需要注意三点:(1)参数中的主机名不一定能和IP地址对应。(2)byte[]遵循big-endian,即IP地址的高位存储在数组的低位。(3)Java中的byte为有符号字节,因此数值上不一定和int的值对应(比如168转为byte后值为-88)。
补充一下关于int和有符号字节的转换:有符号字节的取值范围为-128~127,而8位无符号整型的取值范围为0~255。转换方法如下:
由于DNS查找开销很大,InetAddress类会对查找结果进行缓存,一旦得到一个给定主机的地址,就不会再次查找。这样做可以使得可能会进行重复查找的程序的性能得到提升。不过,这种机制也带来了一些问题,比如无法察觉主机地址的改变等。
可以通过系统属性networkaddress.cache.ttl和networkaddress.cache.negative.ttl控制成功的DNS查找和失败的DNS查找的结果的缓存时间,若设置为-1则永不过期。
使用InetAddress.getByName传入一个IP地址作为参数时,不会检查DNS,只有当请求主机名(getHostName())时才会真正完成DNS查找。这意味着创建出来的InetAddress对象可能不对应任何主机。如果无法成功查找到主机名,主机名会和传入的IP地址保持一致,而不会抛出UnknownHostException异常。
相对来讲,主机名比IP地址稳定的多。在构建InetAddress对象时,应优先考虑使用主机名作为参数传入。
InetAddress包含4个get方法,如下:
主机全名是主机的全称,主机别名是为了方便好记等目的,为主机起的一个“昵称”。下面是用www.oracle.com构建的InetAddress对象调用getHostName()和getCanonicalHostName()的结果:
www.oracle.com
a23-77-22-123.deploy.static.akamaitechnologies.com
至于查看原始字节码的方法,很多时候主要是用来判断协议类型(IPv4地址4字节、IPv6地址16个字节)。
public static int getIpVersion(InetAddress ia){
byte[] address = ia.getAddress();
if(address.length == 4){
return 4;
}else if (address.length == 16) {
return 6;
}else {
return -1;
}
}
public static void main(String[] args) {
try {
InetAddress ia = InetAddress.getByName("192.168.0.0");
System.out.println(getIpVersion(ia));
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
输出:
4
有许多IP地址有着特殊的含义,比如127.0.0.1是本地回送地址,224.0.0.0~239.255.255.255是组播地址等。InetAddress类提供了以下方法对地址类别进行辨别:
InetAddress类还提供了两个isReachable()方法,用于测试节点对当前主机是否可达,原理是traceroute方法。
public boolean isReachable(int timeout) throws IOException
public boolean isReachable(NetworkInterface interface int ttl,int timeout) throws IOException
如果主机在timeout毫秒内响应则返回true,否则返回false。如果出现网络错误则抛出IOException异常。第二个方法允许指定从哪个本地网络接口建立连接,以及生存时间TTL。
Inet4Address与Inet6Address是InetAddress的两个子类,用于区分IPv4地址和IPv6地址。一般来讲,编程人员处于应用层,不需要了解IP地址的细节,因此这两个子类很少用到。
NetworkInterface类表示一个本地IP地址,可能是一个物理接口(额外的以太网卡),也可能是一个虚拟接口(与其他IP地址绑定到同一个物理硬件)。NetworkInterface提供了枚举本地地址的方法。
public static void listAllNetworkInterfaces(){
try {
Enumeration<NetworkInterface> interfaces =
NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface networkInterface =
(NetworkInterface) interfaces.nextElement();
System.out.println(networkInterface);
}
} catch (SocketException e) {
e.printStackTrace();
}
}
除此之外,NetworkInterface类还提供了两个静态工厂方法,用于根据名称或IP地址获取NetworkInterface对象:
public static NerworkInterface getByName(String name) throws SocketException
public static NetworkInterface getByInetAddress(InetAddress address) throws SocketException
获得了NetworkInterface对象后,就可以利用它的一系列get方法获取IP地址、名称等信息。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。