PS:通俗一点的解释都会在引用块中安全
Nothing is true, Everything is permitted.服务器
TCP,全称Transmission Control Protocol,是一种面向链接、可靠的、基于字节流的单播协议。与咱们常说的TCP/IP协议不一样,TCP/IP是一个协议族,涉及到OSI模型中的网络层、应用层和应用层。而咱们要聊的TCP就是在传输层的协议,如今应用的特别普遍的HTTP请求,就是基于TCP的。微信
所谓面向链接很好理解,就像咱们要对远程服务器发出一个指令,首先咱们须要登陆上去。这个登陆就是一个链接的过程。网络
在作数据交换以前,通讯双方必须在彼此创建一条链接。也就是通讯双方都维护了一份对方的信息,好比IP地址和端口号。说到创建链接,就不得不提到经典的三次握手和四次挥手。app
三次握手让通讯双方都明确有一个链接正在创建,也为了确保客户端和服务器同时具备发送和接收的能力。而两次握手作不到这一点。咱们如今从另一个角度来看一下三次握手,那就是为何要三次握手?我两次握手它不香吗?让咱们用一段对话来模拟若是真的采用两次握手,会带来什么问题。tcp
朋友:喂,喂?听获得吗spa
你:听获得…你声音能不能小点code
这就是两次握手。orm
按照人的逻辑来讲,这已是一次正常的对话了是吧,下一步难道不是创建链接吗?说下一步以前,须要先了解作三次握手的目的是什么。三次握手让通讯双方都明确有一个链接正在创建,也为了确保客户端和服务器同时具备发送和接收的能力。blog
咱们来分析一下上面的那段对话。
朋友问你能不能听到,说明朋友具备发送能力;你听到了朋友的问题,说明你具备接收能力
若是只有两次握手,问题在哪儿呢?
站在朋友的角度,他知道你同时具备发送和接收能力
但站在你(服务器)的角度,你只知道朋友具备发送能力,由于你不知道你发的声音能不能小点,他到底有没有收到
服务器不清楚客户端是否有接收能力的状况下,就算数据包真的发出去了,但没法知道客户端是否收到了数据。这样的就是不可靠的链接了。
并且,真实的网络传输中,出现网络延迟是常有的事,若是客户端发送了请求创建链接的数据包,因为网络延迟,数据包没有到达,客户端又发了一次,服务器收到以后创建了链接。
可是当前的链接关闭后,因为网络延迟的没有到达的包到了服务器,服务器又创建了链接,可是此时客户端已经断开了,这样就白白浪费了服务器的资源。
若是以为上面的例子仍是不能让你理解, 为何两次握手不行。请看下面这个终极例子。
朋友:快借我点钱,XX宝帐号123XXXXXXXX
你:好的, 你的账号是123XXXXXXXX吗
。。。。。。(无应答)
你的心里:??????
若是你是被借钱的那个,你敢把钱转过去吗?
简单总结一下两次握手所带来的问题:不可靠,还会形成网络资源的浪费。
上面咱们讨论了为何要三次握手,接下来咱们用几个专业术语来解释一下三次握手的过程。
服务器开始监听某个端口,此时服务器进入了LISTEN
状态
客户端最初是CLOSED
状态,而后向服务器发送一个SYN标志位的数据包,主动发起链接。客户端变成SYN-SENT
状态
服务器接收到客户端的SYN数据包,经过标志位知道了客户端想要创建链接。因而回了客户端一个SYN和ACK,表示收到了请求。服务器的自身状态变为了SYN-RCVD
客户端收到了服务器的ACK,表示服务器知道了客户端想要创建链接。而后客户端再给服务器回了一个ACK表示本身收到了(或者说可以收到)服务器的消息,发送完这个ACK后,客户端的状态变成了ESTABLISH
服务器收到了客户端的ACK,服务器的状态也变成ESTABLISH
老规矩,仍是让咱们用一段对话来模拟TCP的四次挥手。
场景,你跟你的朋友们正在外面high
你:大家继续玩,我就先走了,明天还要上班(第一次)
老铁:(老铁看到你在跟他说话且从你说的话中知道你要走了,老铁也用肢体语言告诉你他知道你要走了)(第二次)
老铁:那好吧, 路上注意安全哈 (第三次)
你:好的,下次再约 (第四次)
这就是通俗版本的四次挥手的解释,下面从专业的角度来看看。
咱们来看一下完整的流程。
最初,客户端和服务器都处于ESTABLISH
状态
客户端想要断开链接,便主动向服务器发送标志位为FIN的数据包。发送以后客户端的状态变为FIN-WAIT-1
,同时客户端也变成了半关闭状态,即没法向服务器发送数据包了,只能接收来自服务器的数据
服务器收到客户端的FIN数据包,状态变为CLOSE-WAIT
,并回给客户端一个表示确认的数据包ACK
客户端收到了ACK以后,状态变为FIN-WAIT-2
而后,服务器向客户端发送FIN数据包,服务器状态变为LAST-ACK
客户端收到FIN数据包,客户端状态变为TIME-WAIT
。而后回一个确认数据包ACK给服务器
而后客户端等待2MSL,若是在这段时间内,没有收到服务器重发的消息,说明服务器收到了ACK
四次挥手到此结束,链接断开
咱们再来模拟一次刚刚的场景。
场景,你跟你的朋友们正在外面high
你:大家继续玩,我就先走了,明天还要上班(第一次)
老铁:(老铁喝high了,反射弧无限延长)
你确定得再说一次啊,给朋友说你要走了,因而你又说了一次。
你:大家继续玩,我就先走了,明天还要上班(第一次)
老铁:(老铁喝high了,反射弧无限延长)
。。。。。。
如此反复
实际状况是,若是是两次挥手,也就是把服务器给客户端的ACK和FIN合并为同一个,若是此时网络出现了延迟,站在客户端的角度来看,客户端会认为刚刚发送的FIN报文并无到达服务器,因而会在再从新发送一次。若是延迟的时间较长,那么客户端将会一直从新发送FIN的TCP报文。
结合抽象和具体的四次挥手,其实就很好理解了,咱们用一个表格来总结一下。
描述状态 | 实际状况 |
---|---|
你和你的朋友在外面high | 客户端和服务器创建了链接 |
你和朋友说你要走了 | 客户端主动向服务器发送FIN,客户端状态变为FIN-WAIT-1 |
你的朋友听到了并理解了你要说的话,并经过肢体语言反馈给你他知道了 | 服务器收到FIN数据包,并回了一个ACK,服务器的状态变为CLOSE-WAIT。客户端收到ACK以后变为FIN-WAIT-2 |
你的朋友说“那好吧, 路上注意安全哈” | 服务器向客户端发送FIN包,服务器变为LAST-CHECK。 |
你说“好的,下次再约” | 客户端收到FIN包后状态变为TIME-WAIT。并回一个ACK给服务器。 |
你迟疑了一下,你的朋友并无挽留你 | 客户端等待2MSL,若是没有收到服务器的重发消息,则说明服务器收到了ACK。 |
你离开了和朋友的聚会 | 四次挥手结束,链接断开 |
MSL,即Maximun Segment LifeTime,报文最大生存时间。为何在TIME-WAIT以后还须要等待2MSL呢?主要是两个缘由,让咱们结合例子来理解一下。
假设你说了“好的,下次再约”。因为你们都在high,声音太大了。致使你的朋友没有听到你说的“好的,下次再约”这句话,而后你转头就走了。
若是你站在你朋友的角度,确定会内心很不爽,好心提醒你,连句作别的话都没有?
这种状况就是服务器并无收到客户端收到的ACK,站在服务器的角度,服务器并不知道客户端收到了本身发的FIN包。也就不会断开链接,可是客户端已经单方面的断开链接了。又形成了服务器的资源浪费,服务器也没法进入正常的关闭链接状态。
一样,你说了”好的, 下次再约“后,你没有确认你的朋友是否听到了,扭头就走。你的朋友也喝多了,此时内心很不爽,骂了一句傻X。
这句话恰好被路过、站到了你刚刚站的位置上的哥们接住了,觉得在说他,内心就很不爽,提着拳头就把你的朋友揍了一顿。
这种状况是指,客户端没有等待2MSL就直接断开,可是服务器此时仍然有些数据包须要发送,或者已经发了出去。可是数据包到了后,此时的端口已经被新的链接占用了,老的TCP报文就会与新链接的TCP报文冲突、混淆。
后面若是我有时间,会继续尝试把枯燥的理论抽象成生活中一些简单的现象而且与专业的知识结合起来的文章风格,来帮助那些看理论知识很吃力的人。其实只要理解了整个思路,是不须要去死记硬背的。
若是文章中有不对的地方,还望各位大佬不吝赐教。
若是你以为这篇文章对你有帮助,还麻烦点个赞,关个注,分个享,留个言
也能够微信搜索公众号【SH的全栈笔记】,固然也能够直接扫描二维码关注
![]()