Internet地址
InetAddress类
InetAddress类是对JavaIP地址的高层表示。大多数其他网络都用到这个类,包括Socket,ServerSocket,URL,DatagramSocket,DatagraPacket
获取域名的IP地址:
InetAddress address = InetAddress.getByName("www.baidu.com");
system.out.println(address);
该方法会与DNS服务器建立一个连接,来查找地址(如果之前查找过,可能会在本地缓存)。参数也可以是其 IP 地址的文本表示形式。如果提供字面值 IP 地址,则仅检查地址格式的有效性。
获取主机名
address.getHostName();
获取主机的所有地址
InetAddress[] addresses = InetAddress.getAllByName("www.oreilly.com");
查找本机地址
InetAddress me = InetAddress.getLocalHost();
如果查找DNS失败,会返回127.0.0.1的IP地址
通过IP地址或主机名创建InetAddress对象
byte[] address = {(byte)192, (byte)168, (byte) 253, 1};
InetAddress IA = InetAddress.getByAddress(address);
InetAddress IA2 = InetAddress.getByAddress("DESKTOP-D1COEVD", address);
System.out.println(IA + "-----" + IA2);
这两个方法不能保证主机一定存在,如果不存在,将会抛出异常
缓存
DNS的查询开销很大,所以InetAddress会缓存查找的结果。一旦得到一个给定的主机的地址,就不会再次查找,即使你为同一个主机创建一个新的InetAddress对象,也不会再次查找地址。但Java对于不成功的DNS查询只缓存10秒。
这些时间可以用系统属性networkaddress.cache.ttl和networkaddress.cache.negative.ttl来控制。第一个属性制定了成功DNS查找结果在java缓存中保留的时间,第二个是不成功的缓存保留时间。
按IP地址查找
可以用getByName()和一个IP地址作为参数来创建一个InetAddress对象,而不检查DNS。这个对象可能是实际上无法连接的主机。由于IP地址没有主机名稳定,大多是采用主机名获取InetAddress对象
安全性问题
从主机名创建一个新的InetAddress对象被认为是潜在的不安全的操作,因为这需要一个DNS查找,因为DNS查找可能会泄漏信息。
获取方法
InetAddress包含4个获取方法,可以将主机名作为字符串返回,将IP地址返回为字符串和字符数组:
public String getHostName();//在不知道主机名的时候进行DNS查询,返回主机名和IP地址
public String getCanonicalHostName();//即使在知道主机名的情况下仍然查询,返回主机名,常用来在一直IP地址的时候查询主机名
public byte[] getAddress();//返回IP地址,可以用来测试时IPV4还是IPV6地址
public String getHostAddress();//返回IP地址
地址类型
java提供了10个测试ip地址类型的方法,像回送地址,通配地址等
连接可达性
InetAddress类有两个isReachable()方法,可以测试一个特定节点对当前主机是否可达(能否建立一个连接),不可达的原因可能有防火墙、 阻塞等
public boolean isReachable(int timeout) throw IOException
public boolean isReachable(NetworkInterface interface, int ttl, int timeout);//指定从哪个本地网络接口建立连接
Object的方法
InetAddress的equals比较的是IP地址,而不是主机名
Inet4Address和Inet6Address
这两个类分别是IPV4和IPV6地址。Inet6Address多了一个isIPv4CompatibleAddress()方法,表示这个IPV6地址是不是IPV4地址填充的
NetworkInterface类
NetworkInterface类表示一个本地IP地址。这可以是一个物理接口,如额外的以太网卡(常见于防火墙和路由器),也可以是一个虚拟接口,与机器的其他IP地址绑定到同一个物理硬件。NetworkInterface类提供了一些方法可以枚举所有本地地址(而不考虑接口),并由他们创建InetAddress对象,然后这些InetAddress对象可用于创建socket、服务器socket等
工厂方法
由于该对象表示物理硬件和虚拟地址,所以不能任意构造。需要通过工厂方法
public static NetworkInterface getByName(String name) throws SocketException
name表示指定名字的网络接口,如果没有这样的接口就返回null。名字的格式与平台有关,unix,以太网接口的形式为eth0,eth1等
public static NetworkInterface getByInetAddress(InetAddress address) throws SocketException
返回与指定IP绑定的接口
public static Enumeration getNetworkInterfaces() throws SocketException
返回所有的网络接口
获取方法
public Enumeration getInetAddresses();
一个网络接口可以绑定多个IP地址。对于这个接口绑定的每一个IP地址都包含一个InetAddress。
public String getName()
返回名字
public String getDisplayName();
获得更加友好的名字
相关程序
查询主机是否是垃圾发送者
通过服务器的黑洞列表查询
public class SpamCheck {
public static final String BLACKHOLE = "sbl.spamhaus.rog";
public static void main(String[] args) {
for (String arg : args) {
if (isSpammer(arg)) {
System.out.println(arg + "is a know spammer.");
} else {
System.out.println(arg + "appears letitimate");
}
}
}
private static boolean isSpammer(String arg) {
try {
InetAddress address = InetAddress.getByName(arg);
byte[] quad = address.getAddress();
String query = BLACKHOLE;
//转换成无符号型
//查询时通过IP地址+BLACKHOLE的形式
for (byte octet : quad) {
int unsignedByte = octet < 0 ? octet + 256 : octet;
query = unsignedByte +"." +query
}
//查询失败将会抛出异常
InetAddress.getByName(query);
return true;
} catch (UnknownHostException e) {
return false;
}
}
}
处理WEB服务器的日志文件
WEB服务器可以记录访问主机的IP地址或者名字,如果是名字需要进行一次DNS请求。这种查询可以用这些类完成(采用多线程)
查询类:
public class LookupTask implements Callable<String>{
private String line;
public LookupTask(String line) {
this.line = line;
}
@Override
public String call() throws Exception {
int index = line.indexOf(" ");
String address = line.substring(0, index);
String theRest = line.substring(index);
String hostname = InetAddress.getByName(address).getHostName();
return hostname + " " + theRest;
}
}
主程序:
public class PooledWeblog {
private final static int NUM_THREADS =4;
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(NUM_THREADS);
Queue<LogEntry> results = new LinkedList<>();
try (BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(new FileInputStream(args[0]), "UTF-8"));) {
for (String entry =bufferedReader.readLine();entry!=null; entry = bufferedReader.readLine()) {
LookupTask task = new LookupTask(entry);
Future<String> future = executorService.submit(task);
LogEntry result = new LogEntry(entry, future);
results.add(result);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static class LogEntry {
String orginal;
Future<String> future;
public LogEntry(String orginal, Future<String> future) {
this.orginal = orginal;
this.future = future;
}
}
}