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; ...
随机推荐
- matlab中画一条折线时怎样显示出每个点折点的数值
举个例子: num=[5,44,62,154,264,365,398,480,619,705,762,728,669,726,890,731,707,696,558,509,444];date=[1. ...
- Go mod graphql-go 的 Replace
现在在项目中大量的使用 graphql,但用的版本是3年前的版本. 3年前包的url:github.com/neelance/graphql-go 现在的url:github.com/graph-go ...
- 思考题:clock类编写
题目 为便于后文理解,这里先补上这份代码前文开的库以及宏定义: #include<cstdio> #include<iostream> #include<string&g ...
- Maven--Maven 安装最佳实践
1.设置 MAVEN_OPTS 环境变量 运行 mvn 命令实际上是执行了 Java 命令,既然是运行 Java,那么运行 Java 命令可用的参数当然也应该在运行 mvn 命令时使用.这个时候,MA ...
- 小白学习之pytorch框架(5)-多层感知机(MLP)-(tensor、variable、计算图、ReLU()、sigmoid()、tanh())
先记录一下一开始学习torch时未曾记录(也未好好弄懂哈)导致又忘记了的tensor.variable.计算图 计算图 计算图直白的来说,就是数学公式(也叫模型)用图表示,这个图即计算图.借用 htt ...
- 12. docker 网络 docker network (docker 网络)
1. 环境准备 编写 Vagrantfile 为 # -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.require_version "> ...
- [WC2010]重建计划(长链剖分+线段树+分数规划)
看到平均值一眼分数规划,二分答案mid,边权变为w[i]-mid,看是否有长度在[L,R]的正权路径.设f[i][j]表示以i为根向下j步最长路径,用长链剖分可以优化到O(1),查询答案线段树即可,复 ...
- Flume(三) —— 断点续传 与 事务
断点续传 # Name the components on this agent a1.sources = r1 a1.sinks = k1 a1.channels = c1 # Describe / ...
- 物联网应用层协议选择和分析--MQTT、CoAP 、HTTP、XMPP、SoAP
MQTT协议 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)最早是IBM开发的一个即时通讯协议,MQTT协议是为大量计算能力有限且工作在低带宽.不 ...
- pom配置项目build jar 包含源码的配置
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> ...