JDK源码看Java域名解析
前言
相关类
|
1
2
3
|
--java.lang.Object --java.net.InetAddress$HostsFileNameService --java.net.InetAddress$PlatformNameService |
JDK选择的方案
|
01
02
03
04
05
06
07
08
09
10
11
|
private static NameService createNameService() { String hostsFileName = GetPropertyAction.privilegedGetProperty("jdk.net.hosts.file"); NameService theNameService; if (hostsFileName != null) { theNameService = new HostsFileNameService(hostsFileName); } else { theNameService = new PlatformNameService(); } return theNameService; } |
接口定义
|
1
2
3
4
5
6
7
|
private interface NameService { InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException; String getHostByAddr(byte[] addr) throws UnknownHostException; } |
HostsFileNameService 类
|
1
|
private static final class HostsFileNameService implements NameService |
lookupAllHostAddr方法
* 根据指定的 hosts 文件路径扫描每一行,如果不存在文件则抛出 FileNotFoundException 异常。
* 遍历每行内容,如果以 # 号开头则表示该行为注释内容,直接忽略,否则继续。
* 标准情况下内容可以为 127.0.0.1 localhost #local,# 号后面为注释内容,所以调用 removeComments 方法去掉 #local,该方法不再贴出。
* 处理后的内容为127.0.0.1 localhost,接着看是否包含了传进来的主机名称有的话则说明是该主机名称映射的 IP 地址,通过 extractHostAddr 方法提取IP地址,值为 127.0.0.1,该方法不再贴出。
* 处理后的内容为127.0.0.1字符串,需要调用 createAddressByteArray 将其转换为 byte 数组以方便得到 InetAddress 对象,该方法不再贴出。
* 将得到的 添加到 ArrayList 对象中,最终转换为 InetAddress 数组并返回。
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException { String hostEntry; String addrStr = null; InetAddress[] res = null; byte addr[] = new byte[4]; ArrayList<InetAddress> inetAddresses = null; try (Scanner hostsFileScanner = new Scanner(new File(hostsFile), "UTF-8")) { while (hostsFileScanner.hasNextLine()) { hostEntry = hostsFileScanner.nextLine(); if (!hostEntry.startsWith("#")) { hostEntry = removeComments(hostEntry); if (hostEntry.contains(host)) { addrStr = extractHostAddr(hostEntry, host); if ((addrStr != null) && (!addrStr.equals(""))) { addr = createAddressByteArray(addrStr); if (inetAddresses == null) { inetAddresses = new ArrayList<>(1); } if (addr != null) { inetAddresses.add(InetAddress.getByAddress(host, addr)); } } } } } } catch (FileNotFoundException e) { throw new UnknownHostException("Unable to resolve host " + host + " as hosts file " + hostsFile + " not found "); } if (inetAddresses != null) { res = inetAddresses.toArray(new InetAddress[inetAddresses.size()]); } else { throw new UnknownHostException("Unable to resolve host " + host + " in hosts file " + hostsFile); } return res; } |
getHostByAddr方法
* 传入的参数为 IP 地址的字节数组,比如new byte[] {127, 0, 0, 1},先调用 addrToString 方法将其转换为”127.0.0.1”字符串,该方法不再贴出。
* 根据指定的 hosts 文件路径扫描每一行,如果不存在文件则抛出 FileNotFoundException 异常。
* 遍历每行内容,如果以 # 号开头则表示该行为注释内容,直接忽略,否则继续。
* 标准情况下内容可以为 127.0.0.1 localhost #local,# 号后面为注释内容,所以调用 removeComments 方法去掉 #local,该方法不再贴出。
* 处理后的内容为127.0.0.1 localhost,接着看是否包含了传进来的 IP 地址,有的话则说明是该 IP 地址对应的主机名称,通过 extractHost 方法提取主机名称localhost,该方法不再贴出。
* 一旦找到主机名称后则不再往下遍历,跳出循环并返回主机名称。
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
public String getHostByAddr(byte[] addr) throws UnknownHostException { String hostEntry; String host = null; String addrString = addrToString(addr); try (Scanner hostsFileScanner = new Scanner(new File(hostsFile), "UTF-8")) { while (hostsFileScanner.hasNextLine()) { hostEntry = hostsFileScanner.nextLine(); if (!hostEntry.startsWith("#")) { hostEntry = removeComments(hostEntry); if (hostEntry.contains(addrString)) { host = extractHost(hostEntry, addrString); if (host != null) { break; } } } } } catch (FileNotFoundException e) { throw new UnknownHostException("Unable to resolve address " + addrString + " as hosts file " + hostsFile + " not found "); } if ((host == null) || (host.equals("")) || (host.equals(" "))) { throw new UnknownHostException("Requested address " + addrString + " resolves to an invalid entry in hosts file " + hostsFile); } return host; } |
PlatformNameService类
类定义如下:
|
1
|
private static final class PlatformNameService implements NameService |
该类即是对操作系统自带的解析方案的封装,核心的两个方法如下,因为这两个方法与操作系统相关,所以通过它们通过 InetAddressImpl 接口调用了对应的本地方法,本地方法分别为 lookupAllHostAddr 和 getHostByAddr。
|
1
2
3
4
5
6
7
|
public InetAddress[] lookupAllHostAddr(String host) throws UnknownHostException{ return impl.lookupAllHostAddr(host); } public String getHostByAddr(byte[] addr) throws UnknownHostException{ return impl.getHostByAddr(addr); } |
lookupAllHostAddr方法
|
结构
|
参数
|
|
typedef struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
char* ai_canonname;
struct sockaddr* ai_addr;
struct addrinfo* ai_next;
}
|
ai_addrlen must be zero or a null pointer
ai_canonname must be zero or a null pointer
ai_addr must be zero or a null pointer
ai_next must be zero or a null pointer
ai_flags:AI_PASSIVE,AI_CANONNAME,AI_NUMERICHOST
ai_family: AF_INET,AF_INET6
ai_socktype:SOCK_STREAM,SOCK_DGRAM
ai_protocol:IPPROTO_IP, IPPROTO_IPV4, IPPROTO_IPV6 etc.
|
getHostByAddr方法
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
JNIEXPORT jstring JNICALL Java_java_net_Inet4AddressImpl_getHostByAddr(JNIEnv *env, jobject this, jbyteArray addrArray) { jstring ret = NULL; char host[NI_MAXHOST + 1]; jbyte caddr[4]; jint addr; struct sockaddr_in sa; memset((char *)&sa, 0, sizeof(struct sockaddr_in)); (*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr); addr = ((caddr[0] << 24) & 0xff000000); addr |= ((caddr[1] << 16) & 0xff0000); addr |= ((caddr[2] << 8) & 0xff00); addr |= (caddr[3] & 0xff); sa.sin_addr.s_addr = htonl(addr); sa.sin_family = AF_INET; if (getnameinfo((struct sockaddr *)&sa, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NAMEREQD)) { JNU_ThrowByName(env, "java/net/UnknownHostException", NULL); } else { ret = (*env)->NewStringUTF(env, host); if (ret == NULL) { JNU_ThrowByName(env, "java/net/UnknownHostException", NULL); } } |
JDK源码看Java域名解析的更多相关文章
- 结合JDK源码看设计模式——桥接模式
前言: 在我们还没学习框架之前,肯定都学过JDBC.百度百科对JDBC是这样介绍的[JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Jav ...
- 结合JDK源码看设计模式——原型模式
定义: 指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.不需要知道任何创建的细节,不调用构造函数适用场景: 类初始化的时候消耗较多资源 new产生的对象需要非常繁琐的过程 构造函数比较 ...
- 结合JDK源码看设计模式——单例模式
定义: 保证一个类仅有一个实例,并提供一个全局访问点 适用场景: 确保任何情况下这个对象只有一个实例 详解: 私有构造器 单利模式中的线程安全+延时加载 序列化和反序列化安全, 防止反射攻击 结合JD ...
- 结合JDK源码看设计模式——简单工厂、工厂方法、抽象工厂
三种工厂模式的详解: 简单工厂模式: 适用场景:工厂类负责创建的对象较少,客户端只关心传入工厂类的参数,对于如何创建对象的逻辑不关心 缺点:如果要新加产品,就需要修改工厂类的判断逻辑,违背软件设计中的 ...
- JDK源码看ArrayList和Vector的一些区别
最近在看JDK源码,从源码的角度记录一下ArrayList和Vector的一些区别 1.new a.不指定长度 Vector默认创建10个元素的数组 public Vector() { this(10 ...
- 从源码看Java集合之ArrayList
Java集合之ArrayList - 吃透增删查改 从源码看初始化以及增删查改,学习ArrayList. 先来看下ArrayList定义的几个属性: private static final int ...
- 结合JDK源码看设计模式——模板方法模式
前言: 相信很多人都听过一个问题:把大象关进冰箱门,需要几步? 第一,把冰箱门打开:第二,把大象放进去:第三,把冰箱门关上.我们可以看见,这个问题的答案回答的很有步骤.接下来我们介绍一种设计模式--模 ...
- 结合JDK源码看设计模式——适配器模式
定义: 将一个类的接口转换成客户期望的另外一个接口(重点理解适配的这两个字),使得接口不兼容的类可以一起工作适用场景: 已经存在的类,它的方法和需求不匹配的时候 在软件维护阶段考虑的设计模式 详解 首 ...
- 从源码看java中Integer的缓存问题
在开始详细的说明问题之前,我们先看一段代码 public static void compare1(){ Integer i1 = 127, i2 = 127, i3 = 128, i4 = 128; ...
随机推荐
- ubuntu服务器上配置tomcat
前言 嗯,最近想在自己的腾讯云服务器上跑个项目玩玩,由于服务器是重装的系统,所以,只能自己手动装tomcat. 不过,tomcat是基于java的,必须又java环境tomcat才能够使用,因此首先要 ...
- Momentum
11.6 Momentum 在 Section 11.4 中,我们提到,目标函数有关自变量的梯度代表了目标函数在自变量当前位置下降最快的方向.因此,梯度下降也叫作最陡下降(steepest desce ...
- jquery判断字符串中是否包含特定字符的方法总结
方法一:使用indexOf() 和lastIndexOf()方法 案例: var Cts = "bblText"; if(Cts.indexOf("Text") ...
- 201409-1 相邻数对 Java
两两比较,注意不要越界就行 import java.util.Arrays; import java.util.Scanner; public class Main { public static v ...
- UML-如何画通信图?
1.链 2.消息 3.自身传递消息 4.消息顺序编号 5.有条件消息 6.互斥的有条件消息 7.循环或迭代 8.调用静态方法 9.多态 10.同步和异步调用
- java时区问题设置,new Date()和系统时间相差8个小时
出现这种问题有可能是服务时间没有修改. import java.text.DateFormat;import java.text.ParseException;import java.text.Sim ...
- Java web之javascript(2020.1.6)
1.js输出: windows.alert()---警告框 document.write()---写到html文档中 innerHTML---写到HTML元素 console.log()---写到浏览 ...
- this, 闭包,箭头函数
闭包写法 //后台每个执行环境都有一个表示变量的对象---变量对象 //例如compare()函数调用 //compare的执行环境而言,其作用域链包含两个变量对象 本地活动对象 全局活动对象 全局变 ...
- 线性齐次递推式快速求第n项 学习笔记
定义 若数列 \(\{a_i\}\) 满足 \(a_n=\sum_{i=1}^kf_i \times a_{n-i}\) ,则该数列为 k 阶齐次线性递推数列 可以利用多项式的知识做到 \(O(k\l ...
- windows下隐藏文件夹
在cmd中找到文件夹所在的路径,然后执行以下命令 隐藏文件:attrib 文件名 +s +h 显示隐藏文件:attrib 文件名 -s -h 后记:attrib指令用于修改文件的属性,文件的常见属性有 ...