资源记录部分
资源记录部分
域名:所请求的域名。
类型:与问题部分查询类型值一样。
类:地址类型,和问题部分查询类值一样。
生存时间:以秒为单位,表示资源记录的生命周期。
资源数据长度:资源数据的长度。
资源数据:按照查询要求返回的相关资源数据。
DNS 解析详解
知道了 DNS 大概是什么,它的域名结构和报文结构,是时候看看到底怎么解析的以及如何保证域名的解析比较稳定和可靠。
DNS 核心系统
根域名服务器(Root DNS Server),大哥,管理顶级域名服务并放回顶级域名服务器 IP,比如"com","cn"。
顶级域名服务器(Top-level DNS Server),每个顶级域名服务器管理各自下属,比如com可以返回 baidu.com 域名服务器的 IP。
权威域名服务器(Authoritative DNS Server),管理当前域名下的 IP 地址,比如 Tencent.com 可以返回 www.tencent.com 的 IP 地址。
域名结构
核心系统
举个例子,假设我们访问"www.google.com"。
访问根域名服务器,这样我们就会知道"com"顶级域名的地址。
访问"com"顶级域名服务器,可知道"google.com"域名服务器的地址。
最后访问"google.com"域名服务器,就可知道"www.google.com"的 IP 地址。
目前全世界有 13 组根域名服务器还有上百太镜像,但是为了让它能力更强,处理任务效率更高,尽量减少域名解析的压力,通常会加一层"缓存",意思是如果访问过了,就缓存,下一次再访问就直接取出,也就是咱么经常配置的"8.8.8.8"等。
操作系统中同样也对DNS解析做缓存,比如说曾访问过"www.google.com"。
其次,还有我们熟知的 hosts 文件,当在操作系统中没有命中则会在 hosts 中寻找。
这样依赖,相当于有了 DNS 服务器,操作系统的缓存和 hosts 文件,能就近(缓存)完成解析就好,不用每次都跑到很远的地方去解析,这样大大减轻的 DNS 服务器的压力。画了一个图,加深印象。
域名解析
DNS 解析过程
嗯?想必应该知道这个过程了,我们再举个例子,假设我们访问 www.qq.com:
客户端发送一个 DNS 请求,请问 qq 你的 IP 的什么啊,同时会在本地域名服务器(一般是网络服务是临近机房)打声招呼
本地收到请求以后,服务器会有个域名与 IP 的映射表。如果存在,则会告诉你,如果想访问 qq,那么你就访问XX地址。不存在则会去问上级(根域服务器):"老铁,你能告诉我 www.qq.com 的 IP 么。”
在 DNS 收到本地 DNS 请求后,发现是 www.qq.com。“哟,这个由.com大哥管理,我马上给你它的顶级域名地址,你去问问它就好了。"
这个时候,本地 DNS 跑去问顶级域名服务器,"老哥,能告诉下“www.qq.com"的 ip 地址码吗",这些顶级域名负责二级域名比如 qq.com。
顶级域名回复:"小本本记好,我给你 www.qq.com 区域的权威 DNS 服务器地址,它会告诉你。”
本地 DNS 问权威 DNS 服务器:"兄弟,能不能告诉我 www.qq.com 对应IP是啥"
权威 DNS 服务器查询后将响应的 IP 地址告诉了本地 DNS,本地服务器将 IP 地址返回给客户端,从而建立连接。
那如果我们写段cs程序都得这么麻烦的?不不,上面的是大佬们做好,我们只需要使用相关库就好了,这里就得说说 Socket 库了。
Socket库
实际上,这是一段程序包含在操作系统的 Socket 库中,我们只需要调用相关的库就可以获得 IP。那 Socket 库又是个什么东西?
库,文库, Github 仓库,总之一定是 xxx 的集合。为了简便开发,大佬们会将很多方法封装为库,开发人员直接调用即可,这样不仅节省编程的工作量,也提高开发的工作效率,但是如果库出了问题,你就可能不是 GG 半会儿了。Socket 亦是如此,提供了一些网络编程相关的库,方便开发人员调用操作系统的网络功能。如下图,当我们调用 gethostbyname 的时候,就会向 DNS 服务器发送查询消息,然后 DNS 服务器进行响应。响应的信息就会包含查询到的 IP 地址,解析器取出 IP 地址并写入指定的内存中,浏览器只需要从内存地址中取出 IP 地址然后加上 HTTP 请求信息交给操作系统大哥即可。
现在我们拿到了 IP 地址,就可以委托协议栈向这个目标 IP 发送信息了,下面我看看使用 Socket 库发送数据的过程。
理解下上图,服务端创建套接字,我们可以想象为一个水管,当服务端监听进入等待状态后,客户端就可以连接服务端并塞数据到管子中,进行数据的收发。当然,如果不想聊天了,任何一方都可以断开,套接字随机也就断开,通信结束。总结为这几个阶段。
创建套接字阶段。
管子连接到服务端套接字。
收发数据。
断开并删除套接字。
那么在具体的实现中是怎样的呢?
创建套接字,调用 socket 函数会返回一个描述符,这个描述符类似于门牌号,通过门牌号就可知道你住在那一房间。随后的通信直接关联此描述符即可。
连接
创建完套接字,我们就得开始建立连接了,可是还是需要协议栈的帮忙,那么协议栈都干了啥呢?