文章插图
可以看到很多编译相关的,我们忽略之,只把主机信息获取的那部分放大:

文章插图
哦吼,时间基本都耗在了 InetAddress.getAddressesFromNameService 这行代码:

文章插图
往下追溯,可知时间基本耗在了 nameService.lookupAllHostAddr:

文章插图

文章插图
再往下就到了native方法:

文章插图
于是我们到 jdk 源码中看看(我用的 jdk8):

文章插图
接下来需要找 getaddrinfo 的实现 , 由于不知道具体的实现源码在哪里,于是我们在网上找一下 Linux 系统的源码作为参考,参见:https://codebrowser.dev/glibc/glibc/sysdeps/posix/getaddrinfo.c.html#getaddrinfo

文章插图
内部的具体实现基本都是和操作系统交互 , 我们简单瞄几眼就行 。另外,在 getaddrinfo 源码中没有找到火焰图给出的调用链,我们暂时不再深入 。

文章插图
目前 , 我们知道了方法 getaddrinfo 会被调用,因此简单写段 c 程序复现一下:
#include<sys/time.h>#include <iostream>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <netdb.h>#include <netinet/in.h>#include <arpa/inet.h>using namespace std;int main(){char* hostname = "xiaoxi666s-MacBook-Pro.local";addrinfo hints, *res;in_addr addr;int err;struct timeval start, end;gettimeofday(&start, NULL);memset(&hints, 0, sizeof(addrinfo));hints.ai_socktype = SOCK_STREAM;hints.ai_family = AF_INET;if((err = getaddrinfo(hostname, NULL, &hints, &res)) != 0){// 打印耗时(异常情况)gettimeofday(&end, NULL);printf("times=%d\n", end.tv_usec - start.tv_usec);printf("error %d : %s\n", err, gai_strerror(err));return 1;}// 打印耗时(正常情况)gettimeofday(&end, NULL);printf("times=%d\n", end.tv_usec - start.tv_usec);addr.s_addr = ((sockaddr_in*)(res->ai_addr))->sin_addr.s_addr;printf("ip addresss: %s\n", inet_ntoa(addr));freeaddrinfo(res);return 0;}
其中的 hostname 即为主机名 xiaoxi666s-MacBook-Pro.local,我们在 Java 项目中调试时也可以看到,上面的程序中直接将其写死 。
运行程序 , 对比下 hosts 文件中 没有添加主机名 和 添加主机名后的输出结果:
# hosts 文件中没有添加主机名times=6431error 8 : nodename nor servname provided, or not known
# hosts 文件中添加主机名times=1789ip addresss: 127.0.0.1
可以看到,当 hosts 文件中没有添加主机名时,根本找不到对应的网络地址(因为 dns 中也没有解析到),添加之后就能返回对应的 ip 127.0.0.1 了 。这里有几个地方需要注意:
- 即使 hosts 文件中添加主机名,标准 Linux 的 getaddrinfo 方法执行时,也会有接近两秒的耗时 , 但我们在 Java 代码中运行时却只有几十毫秒;
- 前文我们使用 Wireshark 抓包时提到,mdns 查询时存在重试机制,但标准 Linux 的 getaddrinfo 方法中没有看到对应的代码;
- 前面提到的5秒返回结果 , 其实不是返回结果,而是超时了 。但标准 Linux 的 getaddrinfo 方法中没有看到对应的超时控制代码;
接着上面的第3点,回到 Java 项目调试一下,看看为什么超时了还能返回结果 。
当 hosts 文件中没有添加主机名时,会返回本机所有的 ip 地址:

文章插图
当 hosts 文件中添加主机名后,只会返回配置的 127.0.01 的 ip 地址:

文章插图
其中,当 hosts 文件中没有添加主机名时,getaddrinfo 调用返回错误码,此时 jdk 会转而调用 lookupIfLocalhost 方法,它内部调用了操作系统的 getifaddrs 方法,以获取本机所有 ip 地址:

文章插图

推荐阅读
- 如何通过执行SQL为低代码项目提速?
- 手机上网很慢怎么处理(怎么样解决手机上网太慢)
- 跳转控制语句break
- 报时机器人的rasa shell执行流程分析
- 工厂想采购一套信息化生产执行系统mes,不知道用哪家比较好?
- 通过Thread Pool Executor类解析线程池执行任务的核心流程
- 无履行能力的法院会强制执行吗 强制执行无能力履行会判刑吗?
- 民间借贷胜诉后怎么申请强制执行 民间借贷胜诉后多久申请强制执行
- 掀式排烟口执行器怎么接线
- 执行预约定价安排是什么意思 预约定价安排是什么意思