本文为原创文章,如需转载请注明出处,谢谢!
概述
1.TCP 为什么要三次握手和四次挥手
2.Http 知识简单总结文中将使用 Client 和 Server 代表客户端和服务端
一、TCP 三次握手建立连接
还是先盗张图,无图无真相。
1.初始状态
一开始的状态比较简单,Server 打开进程并处于 LISTEN(收听)状态,随时准备处理 Client 的连接请求。Client 主动打开进程,准备发送第一条报文。
2. Client 发出连接请求 (第一次握手)
在打算建立 TCP 连接时,Client 向 Server 发出连接请求报文,这时首部中的同部位 SYN=1,同时选择一个初始序号 seq=x。TCP 规定,SYN 报文段不可携带数据,但要消耗一个序号(seq)。这时,TCP 客户进程进入 SYN-SENT(同步已发送)状态。
3.Server 发送确认报文 (第二次握手)
Server 收到建立连接请求后,如果同意建立连接,则向 Client 发送确认报文。确认报文中 SYN 位和 ACK 位都置为1,同时也选择一个初始序号 seq=y。注意,这个报文段也不能携带数据,但同样要消耗一个序号。这时 Server 进程进入 SYN-RCVD(同步收到)状态。
4.Client 再次发送确认报文 (第三次握手)
Client 收到 Server 的确认报文后,还需再向 Server 发出确认。确认报文 ACK=1,确认号 ack=y+1,自己的序号 seq=x+1。TCP 的标准规定,ACK 报文段可以携带数据,如果不携带数据的话则不消耗序号,在这种情况下,下一个数据报文段的序号仍是 seq=x+1。到此时,TCP 连接已经建立完毕,Client 进入 ESTABLISHED(已建立连接)状态。Server 收到 Client 的确认报文后,也进入 ESTABLISHED 状态。
5.补充
- 四次握手:
在第二次握手中,Server 给 Client 发送的报文段,也可拆为两个报文段,先发送确认报文(ACK=1,ack=x+1),然后再发送同步报文段(SYN=1,seq=y),这样的过程就是四报文握手,但效果是一样的。
- 为什么要进行第三次握手?
主要是为了防止失效的连接请求报文又发送到 Server,因而产生错误。
下面具体说说这种情况,Client 向 Server 发出连接请求报文,但是报文在途中丢失了,没能收到 Server 的确认报文,于是 Client 就又发送了一次连接请求,这次连接正常,数据传输完毕后,断开了 TCP 连接。
假设上述情况的第一次连接请求报文没有丢失,而是由于网络节点长时间滞留了,导致延误到连接释放后的某个时间才到达 Server。这时 Server 会再次给 Client 发送确认报文(第二次握手),但是 Client 进程程序并不会理睬确认报文,因为 Client 没有发送连接请求。现在假如没有第三次握手就会建立连接,那么这次滞后的连接请求报文就会导致 TCP 误建立连接,而 Client 却不知已经建立连接,并不会发送数据给 Server,这样 Server 就会一直处于等待状态,这样就白白浪费了 Server 的很多资源。但有了第三次握手就会避免这种问题的发生,虽然延迟的连接请求发送到了 Server,但 Client 不会处理 Server 的确认报文,也不会再次发送确认请求报文,这样 Server 就知道了 Client 并没有真正想建立连接。
二、TCP 四次挥手释放连接
从图中可以看到,Client 和 Server 在已连接的状态下开始进行数据传输,待传输结束后,开始四次握手释放连接。
1.Client 发送释放连接请求 (第一次握手)
首先,Client 发送释放连接报文请求,报文首部的终止控制位 FIN 置 1,序号 seq=u,它等于之前已传送的最后一个数据报文的序号 +1。这时 Client 进入 FIN-WAIT-1 状态,等待 Server 确认。
2.Server 发送确认报文 (第二次握手)
这步和连接时相同,只是报文序号 seq=v,它也等于之前发送的最后数据的序号 +1,ack=u+1。此时,TCP 进入半关闭状态,即 Client 已经没有数据再向 Server 发送了,而 Server 也只有最后一些数据要发送给 Client。同时,Client 收到确认报文后,会进入FIN-WAIT-2 状态。
3.Server 发送释放连接报文 (第三次握手)
Server 发送完最后的数据后,和 Client 第一次握手时一致,发送释放连接报文,FIN=1,seq=w,序号同样是上一次数据报文的序号 +1(半关闭状态时发送的数据),ack=u+1。这时,Server 进入 LAST-ACK(最后确认状态),等待 Client 最后的确认报文。
4.Client 发送最后的确认报文 (第四次握手)
最后 Client 发送确认报文,ACK=1,seq =u+1 (上一次是 u,TCP 规定即使 FIN 报文不携带数据也要消耗一个序号),ack=w+1。之后 Client 进入 TIME-WAIT状态,此时连接还没释放,必须经过时间等待计时器设置的时间 2MSL 后,Client 才进入 CLOSED 状态。时间 MSL 叫做最长报文段寿命
,RFC 793建议设为 2 分钟。也就是说 Client 需要等待4分钟后才可以真正关闭连接然后再去建立下一个连接。
5.补充
为什么 Client 需要等待 2MSL?
(1)假如 Client 最后的 ACK 报文段丢失了,这时 Server 就会重新发送 FIN+ACK 报文给 Client,如果 Client 不等待 2MSL 直接关闭连接,那么 Server 就会一直处于 LAST-ACK 状态,造成了 Server 的资源浪费。而等待 2MSL,Client 就会再次收到 Server 的 FIN+ACK 报文,然后重新给 Server 发送 ACK 报文,确保双方都确认要关闭连接。
(2)假如 ACK 报文段没有丢失,也是在网络中滞留了,这 2MSL 的等待时间可以让滞留的报文传到 Server,保证本连接持续的时间内所生产的报文都从网络中消失,以免影响下一次连接。还有如果不等待 2MSL ,报文滞留也可能导致 Server 资源浪费,原因同 (1)。
三、 HTTP
1.HTTP 的请求过程
- 建立 TCP 连接
- Client 发送请求报文
- Server 发送响应报文
- 释放 TCP 连接
可以看到 HTTP 是完全基于 TCP 连接的应用层协议,HTTP 所做的只是规定 Client 和 Server 需要遵循一定的规则来传输报文,而 HTTP 本身是无连接的
。
2.HTTP/1.0 和 HTTP/1.1
首先来看一张图,图中表示了一次 HTTP 请求所用的时间。其中 RTT(Round-Trip Time) 表示往返时间,就简单理解为时间开销,我们看到 TCP 建立连接就需要一个 RTT,然后 HTTP 请求和响应总共需要一个 RTT。知道了一次 HTTP 的时间开销后,就可以说说 HTTP 1.0 和 1.1的特性了。
HTTP/1.0:非持续连接,即每次请求都要建立 TCP 连接,然后再去请求报文,所以每次都会消耗 2*RTT,这种方式会使得服务器的负担很重。
-
HTTP/1.1:解决了 1.0 的不足,采用了持续连接,即一次请求后仍然保持着这次连接,使同一个 Client 和 Server 可以继续在这条连接上传送 HTTP 报文。HTTP/1.1 还有两种工作方式,
非流水线方式和流水线方式
。(1)非流水线方式:Client 收到前一个响应后才能发出下一个请求,类似于我们编程中的同步。这种方式的缺点就是 Server 发送完一个对象后,其 TCP 连接就处于空闲状态,浪费了资源。
(2)流水线方式:同样解决了非流水线的缺点,Client 可以连续向 Server 发出请求,然后陆续收到 Server 的响应,这样服务器可连续响应,让 TCP 空闲时间减少,提高了文档下载效率。
更新
HTTP 的请求方法
这里只介绍几种常用的方法
GET:获取服务器的某一处资源
POST:起初是为了向服务器输入数据的,但通常用于提交某些数据给服务器,然后服务器处理后返还给客户端。
PUT:与 GET 相反,是向服务器写入某个资源,或用于修改更新服务器的资源,由于 PUT 可更改服务器数据,所以需要密码登录来进行认证。
DELETE:删除服务器的某一处资源,不一定会请求成功,HTTP 规范允许服务器在不通知客户端的情况下撤销请求。
好了,4种方法的概念介绍完了,接下来说一下最常用的 GET 和 POST,面试官常会问 GET 和 POST 有什么区别。具体内容参考这篇GET 和 POST 的本质区别,在本文中我就总结一下结论。
GET 和 POST 本质上都是基于TCP传输数据。GET 每次请求发送一个 TCP 包,包括 header 和 data。POST 每次请求发送 2 个 TCP 包,先发送 header 告知服务器,然后再发送 data。
造成两者有差异的原因是 HTTP 规范和浏览器和服务器的限制,比如你在 GET 请求报文中包含了请求实体,虽然数据传送到了服务器,但有可能服务器只处理 URL 中的参数,并不理会请求体中的内容。