一次http请求的完整请求过程
客户端DNS解析
HTTP进行请求首先对请求的域名进行DNS解析。这里以cn.bing.com
为例。
首先介绍一下DNS,DNS是分布式的域名系统,它使用53端口,支持TCP和UDP,常使用UDP。但是要注意,由于DNS的操作更多在广域网,其分组丢失率和往返时间的不确定性比局域网更大,所以它对UDP进行了扩展,增加了处理超时和重传的功能。
回到DNS解析,如上图,它的解析流程如下:
- 默认先查找HOST文件(该文件记录了一些常用的网址域名其对应的IP地址)
- 如果找到则直接返回IP地址;如果没有就询问DNS本地服务器(这个DNS本地服务器地址又是从哪里来的,这就要说到DHCP协议,简单地说它会动态地给你的电脑设置ip地址,以及发送它的DNS服务器地址给你)。
- 客户端向DNS本地服务器发生
cn.bing.com
的解析请求;DNS本地服务器先会判断是否缓存过该域名,如果有则返回ip地址; - 如果没有则向根域名服务器(根域名服务器的地址是固定的,目前全球有13个根域名解析服务器,这13条记录持久化在本地域名服务器中)发送请求,查询 com 的域名服务器的地址
- 根域名访问返回com的ip地址,同时本地域名服务器进行缓存
- 本地域名服务器获取 com 域名服务器的ip后向 com 域名服务器请求 bing.com 的ip
- com域名访问返回 bing.com 的ip地址,同时本地域名服务器进行缓存
- 获取 bing.com 域名服务器的ip后向 bing.com 域名服务器请求 cn.bing.com 的ip地址
- 最终获取到
cn.bing.com
的IP地址,此时本地域名服务器会将该ip地址缓存起来 - 本地域名服务器向客户端返回结果
第一次握手
- 进入客户端传输层
DNS获取ip地址后,首先需要通过TCP三次握手建立端到端的连接。
TCP第一次握手,不传输数据,只生成TCP报文段首部用来与服务器建立连接。由于请求的是https,其目的端口号为443(如果请求的是http,则目的端口为80),源端口号则为1024-65535之间的任意端口号。SYN同步序号置1,SEQ序列号赋值,MSS与服务器确认最大报文长度
- 进入客户端网络层
之后该报文段被送到送到网络层,由于上面已经知道了目的主机的ip地址,ip协议就可以直接将源ip地址和目的IP地址等字段加到报文段前面封装成ip数据包。
IP数据包在网络层封装好后,就将数据报发送到数据链路层。由于IP协议是不可靠的,当ip数据包因为某种原因被丢弃时,ICMP协议会返回一个错误包给IP协议,告诉它数据包发生了错误.
- 进入客户端数据链路层
进入数据链路层(这里以太网为例),将目的mac地址和源mac地址以及其他字段加到数据包的首部封装成帧。由于不清楚目的地址的mac地址,就需要使用ARP协议通过目的的ip地址获取目的的mac地址。 ARP协议的执行过程为:ARP协议首先查找ARP映射表(即ip映射mac的缓存),如果查找到则直接返回;如果没有则通过发送一个广播到所有子网内的主机询问该ip地址是否为自己的ip。这里有两种情况,如果目标主机在同一子网中,则该目标主机进行回应它的mac地址;如果目标主机不在同一子网中,则ARP协议就返回连接两个子网的路由器(或者网关)的mac地址。之后交于物理层传输,物理层是真正实现数据01序列的传输。
这里需要注意,数据链路层协议是可靠的,点对点的。它具有差错检测、差错控制、拥塞控制等功能,保证数据从主机A到主机B
- 在网络中传输
如图,数据帧经过物理层的传输回到数据链路层,处理接受的数据并将以太网帧头移除,将数据包发送到网络层。如果网络层是路由器,路由器则根据目的ip的网络号来匹配路由表,找到转发数据包的端口,再重复进行ARP协议获取目的mac地址之后发送到数据链路层和物理层。重复上述过程直到到达目的主机。如果如果找不到匹配的网络或主机就返回不可达的信息。
- 到达服务器
到达服务器,经过数据链路层、网络层拆分帧首部、IP首部后将数据段交由TCP来处理。至此第一次握手结束。
第二次握手
上面提到的客户端第一次握手发送的数据段除源端口和目的端口外还有其他字段,比如SYN = 1、MSS = 1024、seq = 10。SYN=1表示请求建立连接,此时seq的初始序号。而MSS是最大报文段长度,表示tcp传输时最大的数据长度,这个参数的目的是为了防止ip分片,提高传输效率。
服务器接收到TCP的SYN数据段后,向客户端发送ACK报文段,其中SYN 、ACK位置1,ack = 接收报文段seq + 1,并设置发送报文seq值。
客户端接收到服务器的ACK报文段,第二次握手结束。
SYN - 创建一个连接 FIN - 终结一个连接 ACK - 确认接收到的数据 seq - 是序列号,这是为了连接以后传送数据用的
第三次握手
客户端接收到服务器的SYN,ACK报文段,发送ACK确定报文段,其中ACK位置1,ack = 接收报文段seq + 1。服务器接收到报文段后,第三次握手结束,一个TCP连接就建立起来了。
发起https请求
- 建立HTTPS安全通信
TCP三次握手后,需要使用SSL/TLS协议建立安全通信。如图(图片来源你知道,HTTPS用的是对称加密还是非对称加密)SSL协议的请求流程为:
1. 客户端向服务器发送https请求,服务器接收到客户端发送的请求,并发送包含(公钥的)数字证书。
2. 客户端接收证书,并进行验证。如果不通过则提示用户是否信任该证书。
3. 如果通过则客户端生成密钥,再通过服务器发送过来的公钥进行加密,并将加密后的密钥发送给服务器。
4. 服务器接收到加密的密钥后通过私钥进行解密
5. 此时客户端和服务器都获得了密钥,之后的HTTP请求就可以通过该密钥进行对称加密
2. 发起一次HTTP请求
之后HTTP封装HTTP报文,发起一次HTTP请求。
进入传输层,不过现在有点不同。这是由于一个HTTP报文一般比MSS大,所以在TCP中,一个HTTP报文会分成多个TCP数据段进行传输,然后在服务器将这些数据段组合起来。最后服务器接收请求报文,并向客户端发送响应报文,客户端接收响应报文。
如果请求数据段在传输途中丢失、乱序、发生堵塞,这时就需要使用TCP的可靠性机制。TCP通过对每个数据段设置超时计时器,当数据段丢失时,TCP一直接收不到确定报文,等到TCP的超时计数器到期,就进行重传来解决数据丢失问题;由于网络的复杂性,数据段到达服务器的顺序可能不同,这时就可以通过TCP的序列号来确保不发生乱序;TCP有滑动窗口、拥塞避免等方式来避免网络堵塞。
注意:MSS不是一成不变的,因为数据传输的链路可能会发送改变,比如其中一个路由器节点出现故障。这就导致了TCP的报文段其大小与HTTP的报文无关,所以说HTTP是面向字节流传输数据的
TCP对HTTP报文进行分组是为了避免IP分片;IP分片是IP协议根据当前链路的MTU对数据包进行分组,与TCP分组不同的是,TCP分组是在服务器端进行重组;而IP分片是在每个节点进行重组。
- 四次挥手断开连接
客户端接收响应报文后,没有数据请求就进行TCP四次挥手断开连接。
客户端发送FIN 报文段,服务器端接收FIN报文段,并发送ACK报文段,允许客户端关闭。此时服务器端还可以发送数据,如果没有数据需要发送,就发送FIN报文段给客户端,客户端发送ACK报文段确定关闭。之后客户端等待2MSL时间后断开连接。至此一次http请求就结束了。
对于HTTP请求的思考
有了数据链路层的可靠性传输为什么还需要TCP可靠性传输?
数据链路层的可靠性传输是主要解决数据在两个主机之间传输过程中因为噪声发生传输错误的问题,即只是保证两台主机间传输的01比特数据不会出错。而TCP的可靠性传输则是主要解决路由器容量不足会丢包、数据乱序到达等问题,即保证数据段到达服务器。
数据链路层的拥塞避免和TCP的拥塞避免的区别,为什么需要这两个拥塞避免算法
个人理解,可以想象成黄河治理,数据链路层的拥塞避免可以看作对洪涝地方修筑堤坝,防止溃堤;而TCP的拥塞避免是对黄河源头进行植树造林,控制源头。
TCP面向连接的本质是什么
TCP面向连接的本质是什么?“连接”:这个连接并不是真正意义上的连接,称之为“虚电路”,其实也并不是说A和B之间震荡建立了一条连接,或者说保证了路由路径是一致的,因为路由选择并不是传输层控制的,传输层负责流量控制和差错控制,因此所有的拥塞控制和路由选择其实是IP协议的工作,所以说,TCP怎能保证路由路径是一样的呢,如果出现网络拥堵,必然会重新选择路径。那么这个连接究竟是什么呢?
答案是:状态和序列号,以及错误校验(可以查看TCP和UDP的请求头,就会发现两者之间的差距了),其实所谓的TCP三次握手请求连接,无非就是初始化一个序列号,保证后面的数据有序到达,同时TCP还支持重传,错误校验,保证数据的可靠性,当然UDP也提供校验。