一 .简单来说 ,HTTP是一个连接 客户端 —服务器 的协议,它指定了客户端发给服务器什么样的消息以及得到什么样的响应。http的特点:
1.支持客户端/服务器的模式 :如上可以连接客户端和服务器端;
2. 简单、快速、灵活 : 请求连接只需要传输 方法 、路径 、请求主体,内容格式多种
3. 无连接的:请求一次结束立即断开(可以通过自身属性keep-live设置http连接的保持时间);
4. 无状态的:无法记住上一次请求的状态(HTTP 协议本身无法解决这个状态,现在通常用cookie 或者session来解决,常见场景cookie中保存token ,登录状态保持);
二 . http的请求过程:
在前端面试中, 经常问到的一个题目, 在浏览器地址栏输入URL 都发生了什么?
抛开HTML渲染, 先http 解析的部分 :HTTP(S)请求地址—— DNS 解析 —— TCP三次握手(建立连接)——发送请求——TCP四次挥手(断开连接);
下面是 TCP/IP的通信的流程图(图片来源网络);
TCP 握手详情 (建立连接协议,三次握手);
1.第一次握手,客户端发送syn包(syn=x)的数据包到服务器,等待服务器确认;
2.第二次握手,服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包
3. 第三次握手,客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED
状态,完成三次握手,
问题:TCP为什么不进行两次握手 ,或者四次握手 ?
在谢希仁著《计算机网络》第四版中,讲 “三次握手” 的目的是 “为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。这个只能算是表因,并不涉及本质。
谢希仁版《计算机网络》中的例子是这样的,“已失效的连接请求报文段” 的产生在这样一种情况下:client 发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达 server。本来这是一个早已失效的报文段。但 server 收到此失效的连接请求报文段后,就误认为是 client 再次发出的一个新的连接请求。于是就向 client 发出确认报文段,同意建立连接。假设不采用 “三次握手”,那么只要 server 发出确认,新的连接就建立了。由于现在 client 并没有发出建立连接的请求,因此不会理睬 server 的确认,也不会向 server 发送数据。但 server 却以为新的运输连接已经建立,并一直等待 client 发来数据。这样,server 的很多资源就白白浪费掉了。采用 “三次握手” 的办法可以防止上述现象发生。例如刚才那种情况,client 不会向 server 的确认发出确认。server 由于收不到确认,就知道 client 并没有要求建立连接。”
其实质是 TCP 的可靠连接是靠 seq( sequence numbers 序列号)来达成的, 所以说,建立可靠连接,需要对客户端和服务器的起始序列号达成共识。
两次握手如上,只有服务器对客户端的起始序列号做了确认,但客户端却没有对服务器的起始序列号做确认,不能保证传输的可靠性。
四次握手演绎
第一步:
客户端A 发送同步信号SYN + A的初始序列号 seq = x
第二步:
服务器端B 确认收到A的同步信号,并记录A的初试序列号到本地,
并向A发送确认信息 ack =x+1。
第三步:
B发送同步信号SYN + B的初始序列号 seq 给客户端A。
第四步:
A确认收到B的同步信号,并记录 B'的初试序列号到本地,并向B发送确认信息 ack = y + 1.
很显然,第二,三步可以合并,只需要三次握手,可以提高连接的速度与效率。
为什么不进行二次握手 或者四次握手?
TCP链接之所以可靠,是因为其链接是面向字节的。
在通信的过程中,协议会给每个字节一个序分配一个序号。三步握手的过程,主要是为了互相确认双方的起始序列号。
如果只进行两次握手,客户端发送链接请求及起始序列号seq = x, 收到 服务器端的起始序列号seq = y及对客户端序列号seq= x 的确认。此时,双方就 客户端的起始序列号达成了共识。
此时,并没有对服务器的起始序列号达成共识,所以就需要进行第三次握手。对B的起始序列号达成共识,不能保证通信的可靠。
如果进行四次握手,在四次握手的过程中,可以把第二、三步合并,这样可以提高连接的速度与效率。
TCP 握手过程传送的数据 , 不包含数据, 三次握手完成后, 客户端和服务器才正式开始传送请求数据,理想状态下,TCP连接建立后, 除非通信双方任何一方主动关闭, 连接会一直保持;
TCP 挥手详情(断开连接协议,四次挥手);
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭 ;客户端 和服务器 的每个方向需要单独关闭,也即 当一方完成它的数据传输后, 需要单独发信息来终止该方向的连接。
第一次挥手: 主动关闭方会发送一个Fin信息,告知被动关闭方: “我不会给你发送数据了。”( 在发出第一个Fin包之后, 如果主动关闭方没有收到确认报文(ACK),还会重新发送Fin信息),此时主动关闭方,还是能够接收数据的;
第二次挥手: 被动关闭方收到Fin包后, 会发送ACK 包 告诉对方: “好的,我知道了。”
第三次挥手: 被动关闭方发送一个Fin 包, 用来关闭被动关闭方到主动关闭方的数据输送,也就是告诉对方 ,我的数据传送完了,我也不给你发送数据了。
第四次挥手: 主动关闭方收到 Fin, 发送ACK : 好的。到此,完成四次挥手。