从DNS到TCP:DNS解析流程和浏览器输入域名访问流程
1 DNS 解析流程
1.1 什么是DNS域名解析
在生活中我们会经常遇到域名,比如说CSDN的域名www.csdn.net,百度的域名www.baidu.com,我们也会碰到IP,现在目前有的是IPV4,IPV6。那这两个有什么区别呢?IP地址是互联网上计算机唯一的逻辑地址,通过IP地址实现不同计算机之间的相互通信,每台联网的计算机都需要通过IP地址来互相联系和分别。
但是由于IP地址是由一串容易混淆且很难记忆的数字串构成,这对我我们日常生活访问不同网站是很困难的。基于此,人们在IP地址的基础上又发展出了一种更容易识别的符号化标识,这种标识由人们自行选择的字母和数字构成,相比IP地址来说更加容易被识别和记忆,逐渐替代IP地址成为互联网用户进行访问互联的主要入口。这种符号化的标识就是域名。
域名虽然说更加容易被用户所接受和使用,但是计算机只能识别纯数字构成的IP地址,不能直接读取域名。因此想要达到访问效果,就需要将域名翻译成IP地址。而DNS域名解析承担的就是这种翻译效果。
1.2 DNS域名解析流程
例如,当我们在浏览器地址中输入www.csdn.net时,DNS会有7个步骤,其中前两个步骤是在本地电脑中完成的,后面8个步骤涉及到真正的域名解析服务器:
1.2.1 第一步 检查浏览器缓存
本地电脑会检查浏览器缓存中有没有这个域名对应的解析过的IP地址,如果缓存中有,这个解析过程就结束。浏览器缓存域名也是有限制的,不仅浏览器缓存大小有限制,而且缓存的时间也有限制,通常情况为几分钟到几个小时不等,域名被缓存的时间限制可以通过TTL属性来设置。这个缓存时间太长和太短都不大好,如果时间太长,一旦域名被解析到的Ip有变化(例如百度作为一个大型的互联网服务提供商,它的IP地址就是动态变化的),会导致被客户端缓存的域名无法解析到变化后的IP地址,这段时间内有一部分用户无法访问网站。如果时间太短,会导致用户每一次访问网站都需要重新解析一次域名。
1.2.2 第二步 查找操作系统缓存
如果浏览器缓存中没有数据,浏览器会查找操作系统缓存中是否有这个域名对应的DNS解析结果。操作系统也有一个域名解析的过程,在Linux中可以通过/etc/hosts文件来设置,而在Windows中可以通过配置 C:\Windows\System32\drivers\etc\hosts文件来设置,用户可以将任何域名解析到能够访问的IP地址。例如,我们在测试时可以将一个域名解析到一台测试的服务器上,这样不用修改任何代码就能测试到单独服务器上的代码的业务逻辑是否正确。正是因为有这种本地DNS解析的规程,所以有黑客就可能通过修改用户的域名来把特定的域名解析到他指定的IP地址上,导致这些域名被劫持。
PS:也有一种情况,电脑会先查找Host文件,再查找浏览器缓存。但是现在有的浏览器会先查找缓存,本文按第二种情况赘述。
1.2.3 第三步 本地DNS服务器
前两个过程无法解析的时候,就需要用到我们网络配置中的“DNS服务器地址”了。操作系统会把这个域名发送给这个本地DNS服务器。每个完整的内网通常都会配置本地DNS服务器,例如用户是在学校或者工作单位接入互联网,那么用户的本地DNS服务器肯定在学校或者工作单位里面。他们一般都会通过缓存域名解析结果,当然缓存时间是会受到域名的失效时间控制的。大约80%的域名解析到这里就结束了,后续的DNS迭代和递归也是由本地DNS服务器配置。
windows配置方式:
控制面板->网络和共享中心->更改适配器设置->选中目标适配器右键选择属性->IPV4或者IPV6,然后配置DNS地址。
1.2.4 第四步 根域名服务器
如果本地DNS服务器没有命中,则本地域名服务器向上级域名服务器进行迭代查询,并首先向根域名服务器发起请求
1.2.5 第五步 顶级域名服务器
由根DNS服务器返回给本地DNS域名服务器一个顶级DNS服务器地址。
1.2.6 第六步 Name Server域名服务器
接受请求的顶级DNS服务器查找并返回此域名对应的Name Server域名服务器的地址,这个Name Server服务器就是我们需要访问的网站域名提供商的服务器,其实该域名的解析任务就是由域名提供商的服务器来完成。比如我要访问www.XXXX.com,而这个域名是X公司注册获得的,那么X公司的服务器上就会有www.XXXX.com的相关信息。
Name Server服务器会查询存储的域名和IP的映射关系表,再把查询出来的域名和IP地址等等信息,连同一个TTL值返回给本地DNS服务器。
1.2.7 第七步 IP和TTL值
返回该域名对TTL值,本地DNS服务器会缓存这个域名和IP的对应关系,缓存时间由TTL值控制。把解析的结果返回给本地电脑,本地电脑根据TTL值缓存在本地缓存中,域名解析过程结束在实际的DNS解析过程中。
可能还不止这七个步骤,例如Name Server可能有很多级,或者有一个GTM来负载均衡控制,这都有可能会影响域名解析过程。
2 浏览器输入域名访问整个流程
2.1 第一步 DNS域名解析
具体见上文。
2.2 第二步 建立TCP连接
在经过DNS解析之后,浏览器已经获取了对应网站的IP地址,通过“三次握手”连接到网站服务器。
2.2.1 什么是三次握手?
建立一个 TCP 连接需要“三次握手”,缺一不可:
- 一次握手:客户端发送带有 SYN(SEQ=x) 标志的数据包 -> 服务端,然后客户端进入 SYN_SEND 状态,等待服务端的确认;
- 二次握手:服务端发送带有 SYN+ACK(SEQ=y,ACK=x+1) 标志的数据包 –> 客户端,然后服务端进入 SYN_RECV 状态;
- 三次握手:客户端发送带有 ACK(ACK=y+1) 标志的数据包 –> 服务端,然后客户端和服务端都进入ESTABLISHED 状态,完成 TCP 三次握手。
当建立了 3 次握手之后,客户端和服务端就可以传输数据了。
2.2.2 为什么要进行3次握手?
三次握手的目的是建立可靠的通信信道,说到通讯,简单来说就是数据的发送与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的。
- 第一次握手:Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常
- 第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:对方发送正常,自己接收正常
- 第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常
三次握手就能确认双方收发功能都正常,缺一不可。
更详细的解答可以看这个:TCP 为什么是三次握手,而不是两次或四次? - 车小胖的回答 - 知乎 。
2.3 第三步 发送HTTP请求
TCP三次握手之后,客户端和服务器端成功建立了连接,之后浏览器会向服务器特定端口发送HTTP请求。
以Chrome 浏览器为例,按下 F12 即可进入开发者模式,Network 一栏查看HTTP请求的具体报文。
一个 HTTP 报文由请求行(Request Line)、请求头部(Request Headers)、空行(Blank Line)以及请求体(Request Body)构成,请求行中规定了请求方法、URI 以及 HTTP 的版本,关于每个字段的详细解释,之前的小节已经进行了阐述。
2.4 第四步 服务器端解析请求
当一个 HTTP 请求打进服务器之后,一般的流程是:网关层(例如Ngnix)最先获取请求,然后路由转发到具体的Web服务,经过一段业务逻辑之后,可能还会查询数据库,最后将处理的结果返回给浏览器客户端。
对于后端开发程序员来说,日常的工作就集中在服务器端,特别是流程图中的"Web业务服务"这块,例如基于 Spring 框架、Django 框架或者ThinkPHP 框架进行业务逻辑开发和上线。
2.5 第五步 返回HTTP响应
服务器端处理业务结果之后,也要返回 HTTP 响应,HTTP 响应由状态行(Status Line)、响应头部(Response Headers)、空行(Blank Line)以及响应体(Response Body)构成,关于每个部分的细节也不再赘述。需要特别注意的是,响应体中的各种错误码定义:
2.6 第六步 TCP四次挥手
当浏览器获取了域名对应的页面信息,为了避免服务器和客户端双方的资源损耗,客户端会请求断开 TCP 连接,和三次握手的过程相似。
断开一个 TCP 连接则需要“四次挥手”,缺一不可,TCP 四次挥手的过程可以总结为::
- 第一次挥手:客户端发送一个 FIN(SEQ=x) 标志的数据包->服务端,用来关闭客户端到服务端的数据传送。然后客户端进入 FIN-WAIT-1 状态。
- 第二次挥手:服务端收到这个 FIN(SEQ=X) 标志的数据包,它发送一个 ACK (ACK=x+1)标志的数据包->客户端 。然后服务端进入 CLOSE-WAIT 状态,客户端进入 FIN-WAIT-2 状态。
- 第三次挥手:服务端发送一个 FIN (SEQ=y)标志的数据包->客户端,请求关闭连接,然后服务端进入 LAST-ACK 状态。
- 第四次挥手:客户端发送 ACK (ACK=y+1)标志的数据包->服务端,然后客户端进入TIME-WAIT状态,服务端在收到 ACK (ACK=y+1)标志的数据包后进入 CLOSE 状态。此时如果客户端等待 2MSL 后依然没有收到回复,就证明服务端已正常关闭,随后客户端也可以关闭连接了。
只要四次挥手没有结束,客户端和服务端就可以继续传输数据
2.6.1 为什么需要四次挥手?
TCP 是全双工通信,可以双向传输数据。任何一方都可以在数据传送结束后发出连接释放的通知,待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后就完全关闭了 TCP 连接。
举个例子:A 和 B 打电话,通话即将结束后。
- 第一次挥手:A 说“我没啥要说的了”
- 第二次挥手:B 回答“我知道了”,但是 B 可能还会有要说的话,A 不能要求 B 跟着自己的节奏结束通话
- 第三次挥手:于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了”
- 第四次挥手:A 回答“知道了”,这样通话才算结束。
2.6.2 四次挥手需要等待2MSL的意义
第四次挥手时,客户端发送给服务端的 ACK 有可能丢失,如果服务端因为某些原因而没有收到 ACK 的话,服务端就会重发 FIN,如果客户端在 2*MSL 的时间内收到了 FIN,就会重新发送 ACK 并再次等待 2MSL,防止 Server 没有收到 ACK 而不断重发 FIN。
MSL(Maximum Segment Lifetime) : 一个片段在网络中最大的存活时间,2MSL 就是一个发送和一个回复所需的最大时间。如果直到 2MSL,Client 都没有再次收到 FIN,那么 Client 推断 ACK 已经被成功接收,则结束 TCP 连接。
2.7 浏览器解析HTML
服务器返回给客户端的是 HTML 以及 CSS、Javascript 代码,要展示为静态页面,还需要经过浏览器的解析行为。
浏览器内核引擎解析 HTML 文档并且将标签转换为 DOM(Document Object Model,文档对象模型)树的 DOM 节点,不同浏览器的渲染解析流程大同小异。
同时,浏览器内核引擎还会解析 CSS 生成 CSS 规则树,按照从右到左的顺序读取选择器。
另外,在浏览器中还有个"JS脚本解析器",解析 HTML 和 CSS 是多线程同时执行的,CSS 解析失败不会影响 HTML 内容的解析,但是如果 JS 脚本解析过程中触发了异常,会直接终止 HTML 内容的解析。关于更详细的解析动作,作为后端开发,我们不需要了解太多,这块也不会作为面试考察的内容。
更详细的可以拜读此篇文章https://zhuanlan.zhihu.com/p/166440446