Java 网络编程 -- IP地址
2017-04-09 本文已影响0人
顾树旺
InetAddress类
- java.net.InetAddress类是Java对IP地址的高层表示。
- 包括IPv4和IPv6的表示。
- 一般来说,包括一个“主机名”和一个“IP地址”。
- 大多数其他网络类都要使用到这个类,包括Socket、ServerSocket、URL、DatagramSocket、DatagramPacket等。
静态工厂方法
- getByName(String url)
- getLocalHost()
- getByAddress()
- getAllByName()
getByName(String url)方法
InetAddress.getByName("www.xxx.com")
- 会建立与本地DNS服务器的一个连接。
- 如果之前查找过这个主机,信息可能在本地缓存,这时不需要建立网络连接。
- 如果DNS服务器找不到这个地址,会抛出
UnknownHostException
,是IOException
的一个子类。 - 可以按IP地址反向查找,如果查找的地址没有相应的主机名,
getHostName()
就会返回提供的点分地址。 - 参数为IP地址时,不检查DNS,在调用
getHostName()
时,才会检查DNS。
示例:
try {
InetAddress address = InetAddress.getByName(www.xxx.com);
System.out.println(address);
} catch (UnknownHostException ex) {
System.out.println("Counld not find www.xxx.com");
}
InetAddress address = InetAddress.getByName("208.201.239.100");
System.out.println(address.getHostName());
getLocalHost()方法
-
getLocalHost()
会为运行这个代码的主机返回一个InetAddress
对象。 - 这个方法尝试连接DNS来得到一个真正的主机名和IP地址。如果失败,就会返回“会送地址”,即主机名
localhost
和点分四段地址127.0.0.1
。
示例:
try {
InetAddress address = InetAddress.getLocalHost();
System.out.println(address);
} catch (UnknownHostException ex) {
System.out.println("Could not find this computer's address.")
}
getByAddress()方法
getByAddress()
方法,不与DNS交互。可以为不存在或无法解析的主机创建地址。
方法原型:
public static InetAddress getByAddress(byte[] addr) throws UnKnownHostException
public static InetAddress getByAddress(String hostname, byte[] addr) throws UnknownHostExeption
示例:
byte[] address = {107, 23, (byte)216, (byte)196};
InetAddress lessWrong = InetAddress.getByAddress(address);
InetAddress lessWrongWithName = InetAddress.getByAddress("lesswrong.com", address);
- 需要把地址中的大数字转换为字节。
- 这两个方法不能保证这个主机一定存在,或者主机名能正确地映射到IP地址。
- 只有当作为address的参数传入的字节数组大小不合法时(不是4字节,也不是16字节),这两个方法才会抛出
UnknownHostException
。
getAllByName()方法
- 如果
www.xxx.com
实际有多个地址,getHostName()
返回哪一个地址是不确定的。 - 可以调用
getAllByName()
会返回一个InetAddress
数组。
示例:
try {
InetAddress[] addresses = InetAddress.getAllByName("www.xxx.com");
for (InetAddress address : addresses) {
System.out.println(address);
}
} catch (UnknownHostException ex) {
System.out.println("Cound not find www.xxx.com");
}
获取方法
- InetAddress有几个获取方法:
- public String getHostName()
- public String getCanonicalHostName()
- public byte[] getAddress()
- public String getHostAddress()
- 没有对应的
setHostName()
和setAddress()
方法,这说明java.net
之外的包无法在后台改变InetAddress
对象的字段。这使得InetAddress
不可变,因此是“线程安全”的。
getHostName()方法
- 返回一个String,包含主机名,和IP地址。
- 如果没有主机名,或者安全管理器组织确定主机名,就会返回点分四段式的数字IP地址。
getCanonicalName()方法
-
getHostName()
只是在不知道主机名时,才会联系DNS。 -
getCanonicalHostName()
知道主机名时,也会联系DNS,可能会替换原来缓存的主机名。
getAddress() 方法
- 获取IP地址,会以网络字节顺序将IP地址作为字节数组返回。
- Java没有“无符号字节”这种基本数据类型。值大于127的字节会当做负数。因此需要做一些调整。
- 通过判断返回字节数组的元素个数,来确定是IPv4还是IPv6。
int unsignedByte = signedByte < 0 ? signedByte + 256 : signedByte;
地址类型
Java提供了10个方法来测试InetAddress
对象是否符合某个标准。
- public boolean isAnyLocalAddress()
- public boolean isLoopbackAddress()
- public boolean isLinkLocalAddress()
- public boolean isSiteLocalAddress()
- public boolean isMulticastAddress()
- public boolean isMCGlobal()
- public boolean isMCNodeLocal()
- public boolean isMCLinkLocal()
- public boolean isMCSiteLocal()
- public boolean isMCOrgLocal()
测试可达性
-
InetAddress
类有两个isReachable()
方法。 - 可以测试一个特定节点对当前主机是否可达(能否建立一个网络连接)。
方法原型
public boolean isReachable(int timeout) throws IOException
public boolean isReachable(NetworkInterface, int ttl, int timeout) throws IOException
- 这些方法使用traceroute(更确切的讲,是ICMP echo请求)查看指定地址是否可达。
- 如果主机在timeout毫秒内响应,则方法返回true;否则返回false。如果出现网络错误,则抛出IOException异常。
- 第二个方法还允许制定从哪个“本地网络接口”建立连接,以及“生存时间”。
Object方法
-
equals()
和hashCode()
方法,只根据IP地址,和主机名无关。 -
toString()
方法,打印主机名/IP地址
。
Inet4Address和Inet6Address
public final class Inet4Address extends InetAddress
public final class Inet6Address extends InetAddress
- 这两个类专门用于IPv4和IPv6。
- Inet6Address增加了一个
isIPv4CompatibleAddress()
。
缓存
- 由于DNS查找的开销可能很大,所以InetAddress类会缓存查找的结果。
- 一旦得到一个给定主机的地址,就不会再次查找,即使为统一主机创建一个新的
InetAddress
对象,也不会再次查找地址。 - Java对于不成功的DNS查询只缓存10秒。
- 缓存时间,可以用系统属性
networkaddress.cache.ttl
和networkaddress.cache.negative.ttl
来控制。-1
表示“永不过期”。 - 除了在
InetAddress
类中的本地缓存,本地主机、本地域名服务器、Internet上其他地方的DNS服务器也会缓存各种查询的结果。对此,Java没有提供相关控制方法。
NetworkInterface类
-
NetworkInterface
类表示一个“本地IP地址”。 - 可以是一个“物理接口”,也可以是一个“虚拟接口”。
工厂方法
public static NetworkInterface getByName(String name) throws Socketexception
public static NetworkInterface getByInetAddress(InetAddress address) throws SocketException
public static Enumeration getNetworkInterfaces() throws SochetException
getByName()方法
- 返回一个
NetworkInterface
对象,表示有指定名字的网络接口。 - 如果没有这样一个接口,就返回
null
。 - 如果在查找相关网络接口时,底层网络栈遇到问题,会抛出一个
SocketException
异常。 - 名字的格式与平台有关。
- UNIX系统上,以太网接口的形式为
eth0
、eth1
等。本地回送地址的名字可能类似lo
。 - Windows上,名字类似
CE31
和ELX100
等。
try {
NetworkInterface ni = NetworkInterface.getByName("eth0");
if (ni = null) {
System.out.println("No such interface: eth0");
}
} catch (SocketException ex) {
System.out.println("Could not list sockets.");
}
getByInetAddress()方法
和getByName()
类似。
// ...
InetAddress local = InetAddress.getByName("127.0.0.1");
NetworkInterface ni = NetworkInterface.getByInetAddress(local);
// ...
getNetworkInterfaces()方法
返回本地主机上的所有网络接口.
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface ni = interfaces.nextElement();
System.out.println(ni);
}
获取方法
public Enumeration getInetAddresses()
public String getName()
public String getDisplayName()
有了NetworkInterface
对象,就可以查询其IP地址和名字。
getInetAddresses()方法
一个网络接口可以绑定多个IP地址,这个方法返回绑定的所有IP地址。
NetworkInterface eth0 = NetworkInterface.getByName("eth0");
Enumeration addresses = rth0.getInetAddresses();
while (addresses.hasMoreElements()) {
System.out.println(addresses.nextElement());
}
getDisplayName()
声称可以返回更好的名字。