1. getByName
public static InetAddress getByName(String host) throws UnknownHostException { ???return InetAddress.getAllByName(host)[0];}public static InetAddress[] getAllByName(String host) throws UnknownHostException { ???return getAllByName(host, null);}private static InetAddress[] getAllByName(String host, InetAddress reqAddr) throws UnknownHostException { ??????// 1. host == null || host.length() == 0 ??????// ???loopbackAddress(与系统属性java.net.preferIPv6Addresses相关):Inet4Address(localhost/127.0.0.1) || Inet6Address(localhost/::1) ??????// 2. host表示一个IP地址 ??????// ???Inet4Address(null/IPAddressUtil.textToNumericFormatV4(host)) || Inet6Address(null/IPAddressUtil.textToNumericFormatV6(host)) ???... ... ???return getAllByName0(host, reqAddr, true);}private static InetAddress[] getAllByName0 (String host, InetAddress reqAddr, boolean check) throws UnknownHostException ?{ ???... ... ???InetAddress[] addresses = getCachedAddresses(host); // 在缓存中查找记录 ???if (addresses == null) { ???????addresses = getAddressesFromNameService(host, reqAddr); // 请求域名解析 ???} ???if (addresses == unknown_array) // 存在失败记录 || 域名解析失败 ???????throw new UnknownHostException(host); ???return addresses.clone();}
1)InetAddress.Cache
static final class CacheEntry { ???CacheEntry(InetAddress[] addresses, long expiration) { ???????this.addresses = addresses; ???????this.expiration = expiration; ???} ???InetAddress[] addresses; // 地址 ???long expiration; // 过期时间}static final class Cache { ???private LinkedHashMap<String, CacheEntry> cache; ???private Type type; ???enum Type {Positive, Negative}; ???public Cache(Type type) { ???????this.type = type; ???????cache = new LinkedHashMap<String, CacheEntry>(); ???} ???private int getPolicy() { // 缓存过期时间 ???????if (type == Type.Positive) { ???????????return InetAddressCachePolicy.get(); // -Dsun.net.inetaddr.ttl=-1(启动参数) || networkaddress.cache.ttl=-1(配置文件) ???????} else { ???????????return InetAddressCachePolicy.getNegative(); // -Dsun.net.inetaddr.negative.ttl=10(启动参数) || networkaddress.cache.ttl=-1(配置文件) ???????} ???} ???public Cache put(String host, InetAddress[] addresses) { ???????int policy = getPolicy(); ???????if (policy == InetAddressCachePolicy.NEVER) { // 0:不缓存 ???????????return this; ???????} ???????if (policy != InetAddressCachePolicy.FOREVER) { // 非永久缓存:需要清除过期记录 ???????????LinkedList<String> expired = new LinkedList<>(); ???????????long now = System.currentTimeMillis(); ???????????for (String key : cache.keySet()) { ???????????????CacheEntry entry = cache.get(key); ???????????????if (entry.expiration >= 0 && entry.expiration < now) { // 当前记录已过期 ???????????????????expired.add(key); ???????????????} else { // 当前记录未过期 ???????????????????break; // 后续记录的插入时间肯定比当期记录晚 ???????????????} ???????????} ???????????for (String key : expired) { // 清除过期记录 ???????????????cache.remove(key); ???????????} ???????} ???????long expiration; ???????if (policy == InetAddressCachePolicy.FOREVER) { // -1:永久缓存 ???????????expiration = -1; ???????} else { // 非永久缓存 ???????????expiration = System.currentTimeMillis() + (policy * 1000); // 过期时间:policy秒 ???????} ???????CacheEntry entry = new CacheEntry(addresses, expiration); ???????cache.put(host, entry); // 添加记录 ???????return this; ???} ???public CacheEntry get(String host) { ???????int policy = getPolicy(); ???????if (policy == InetAddressCachePolicy.NEVER) { // 一定没有数据 ???????????return null; ???????} ???????CacheEntry entry = cache.get(host); // 获取记录 ???????if (entry != null && policy != InetAddressCachePolicy.FOREVER) { // 非永久缓存 ???????????if (entry.expiration >= 0 && entry.expiration < System.currentTimeMillis()) { // 检查是否过期 ???????????????cache.remove(host); ???????????????entry = null; ???????????} ???????} ???????return entry; ???}}
2)getCachedAddresses
private static boolean addressCacheInit = false; // 缓存未初始化static InetAddress[] unknown_array; // 域名解析失败时使用的地址private static Cache addressCache = new Cache(Cache.Type.Positive); // 正面缓存private static Cache negativeCache = new Cache(Cache.Type.Negative); // 负面缓存private static final HashMap<String, Void> lookupTable = new HashMap<>();private static InetAddress[] getCachedAddresses(String hostname) { ???hostname = hostname.toLowerCase(); ???synchronized (addressCache) { ???????cacheInitIfNeeded(); ???????CacheEntry entry = addressCache.get(hostname); // 在正面缓存中查找记录 ???????if (entry == null) { ???????????entry = negativeCache.get(hostname); // 在负面缓存中查找记录 ???????} ???????if (entry != null) { ???????????return entry.addresses; // return 缓存中记录的地址 ???????} ???} ???return null; // 在缓存中未找到记录}private static void cacheInitIfNeeded() { ???assert Thread.holdsLock(addressCache); ???if (addressCacheInit) { ???????return; ???} ???unknown_array = new InetAddress[1]; // 大小为1 ???unknown_array[0] = impl.anyLocalAddress(); // Inet4Address(0.0.0.0/0.0.0.0) || Inet6Address(::/::) ???addressCache.put(impl.anyLocalAddress().getHostName(), unknown_array); // {0.0.0.0, 0.0.0.0} || {::, ::} ???addressCacheInit = true;}
3)getAddressesFromNameService
private static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr) throws UnknownHostException { ???... ... ???if ((addresses = checkLookupTable(host)) == null) { // 是否正在解析该host ? 等待 ???????try { ???????????for (NameService nameService : nameServices) { ???????????????try { ???????????????????addresses = nameService.lookupAllHostAddr(host); // 向该域名服务请求域名解析 ???????????????????success = true; ???????????????????break; // 只要有一个域名服务成功解析host则退出循环 ???????????????} catch (UnknownHostException uhe) { ???????????????????// 1. 若host = localhost,则addresses = [loopbackAdress] & 退出循环 ???????????????????// 2. 否则准备抛异常(success = false & 记录uhe) & 继续循环 ???????????????????... ... ???????????????} ???????????} ???????????// 若reqAddr不为空 && addresses中存在与reqAddr相等的InetAddress,则将该InetAddress挪到第一个位置 ???????????... ... ???????????cacheAddresses(host, addresses, success); // 缓存记录 ???????????// ????????????... ... ???????} finally { ???????????updateLookupTable(host); // 唤醒所有等待解析该host的线程 ???????} ???} ???return addresses;}private static InetAddress[] checkLookupTable(String host) { ???synchronized (lookupTable) { ???????if (lookupTable.containsKey(host) == false) { // 其它线程是否也在请求解析该host ???????????lookupTable.put(host, null); // 告知之后请求解析该host的线程:正在进行域名解析 ???????????return null; // return & 进行域名解析 ???????} ???????while (lookupTable.containsKey(host)) { // 域名解析尚未完成 ???????????try { ???????????????lookupTable.wait(); // 等待 ???????????} catch (InterruptedException e) { ???????????} ???????} ???} ???InetAddress[] addresses = getCachedAddresses(host); // 在缓存中查找记录 ???if (addresses == null) { // 在缓存中未找到记录 ???????synchronized (lookupTable) { ???????????lookupTable.put(host, null); ???????????return null; // return & 继续进行域名解析 ???????} ???} ???return addresses; // 在缓存中找到记录}private static void cacheAddresses(String hostname, InetAddress[] addresses, boolean success) { ???hostname = hostname.toLowerCase(); ???synchronized (addressCache) { ???????cacheInitIfNeeded(); ???????if (success) { // 域名解析成功 ???????????addressCache.put(hostname, addresses); // 在正面缓存中记录 ???????} else { // 域名解析失败 ???????????negativeCache.put(hostname, addresses); // 在负面缓存中记录 ???????} ???}}private static void updateLookupTable(String host) { ???synchronized (lookupTable) { ???????lookupTable.remove(host); // 告知所有等待解析该host的线程:域名解析完毕 ???????lookupTable.notifyAll(); // 唤醒所有等待解析该host的线程 ???}}
2. getByAddress
public static InetAddress getByAddress(byte[] addr) throws UnknownHostException { ???return getByAddress(null, addr);}public static InetAddress getByAddress(String host, byte[] addr) throws UnknownHostException { ???// host截子串:[host] -> host ???... ... ???if (addr != null) { ???????if (addr.length == Inet4Address.INADDRSZ) { // 4字节:IPv4地址 ???????????return new Inet4Address(host, addr); ???????} else if (addr.length == Inet6Address.INADDRSZ) { // 16字节:IPv6地址 ???????????byte[] newAddr = IPAddressUtil.convertFromIPv4MappedAddress(addr); // 转IPv4地址 ???????????if (newAddr != null) { // 装换成功 ???????????????return new Inet4Address(host, newAddr); ???????????} else { // 转换失败 ???????????????return new Inet6Address(host, addr); ???????????} ???????} ???} ???throw new UnknownHostException("addr is of illegal length");}
3. getHostName
public String getHostName() { ???return getHostName(true);}String getHostName(boolean check) { ???if (holder().getHostName() == null) { ???????holder().hostName = InetAddress.getHostFromNameService(this, check); // 根据IP地址请求域名 ???} ???return holder().getHostName();}private static String getHostFromNameService(InetAddress addr, boolean check) { ???String host = null; ???for (NameService nameService : nameServices) { ???????try { ???????????host = nameService.getHostByAddr(addr.getAddress()); // 根据IP地址向该域名服务请求域名 ???????????... ... ???????????// prevent spoofing??? ???????????InetAddress[] arr = InetAddress.getAllByName0(host, check); // 反向由域名获取InetAddress:可能将进行域名解析 ???????????boolean ok = false; ???????????if(arr != null) { ???????????????for(int i = 0; !ok && i < arr.length; i++) {// 在arr中查找与addr(IP地址)相等的InetAddress ???????????????????ok = addr.equals(arr[i]); // InetAddress.equals:IP地址相等 ???????????????} ???????????} ???????????if (!ok) { // arr == null || 在arr中未找到与addr(IP地址)相等的InetAddress ???????????????host = addr.getHostAddress(); // IP地址字符串 ???????????????return host; ???????????} ???????????break; ???????} catch (SecurityException e) { ???????????host = addr.getHostAddress(); // IP地址字符串 ???????????break; ???????} catch (UnknownHostException e) { ???????????host = addr.getHostAddress(); // IP地址字符串 ???????} ???} ???return host;}
InetAddress之域名解析
原文地址:http://www.cnblogs.com/bjorney/p/8093396.html