TCP协议的三次握手和四次挥手
一、知识回顾
何为TCP协议?
TCP协议是一种面向连接的,可靠的,基于字节流的传输层通信协议,采用全双工通信。
二、TCP建立连接时的三次握手
1、直观理解版:
三次握手即表示TCP连接时,客户端(以下用A表示)和服务端(以下用B表示)之间建立联系的三个过程:
First--> A向B发起连接请求,此时:A---->B;
Second--> B收到A的发送信号,并且向A发送确认消息,此时:B---->A;
Third--> A收到B的确认信号,并向B发送确认信号,此时:A---->B。
分析:通过第一次握手,B知道A发起了连接请求;第二次握手,A知道B此时能发送数据;第三次握手,
B知道A能够接收数据。至此,A与B的连接建立完成。
2、核心原理版:
第一次握手:建立连接时,客户端发送syn包(syn=j)至服务器,并进入SYN_SENT状态,等待服务器确认。
SYN(Synchronize Sequence Numbers):同步序列编号。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自身也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态。
第三次握手:客户端收到服务器·的SYN+ACK包,向服务器发送确认包ACK(ack+1),此确认包发送完毕后,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
三次握手完成连接成功后,客户端和服务器间便可进行通信,数据传递等操作。
示意图如下:
3、那么问题来了,为什么是三次握手呢?而不是两次或者四次呢?
<1>通俗版本解释:
先看一段对话,是知乎上一位匿名用户的回帖。
三次握手:
“喂,你听得到吗?”
“我听得到呀,你听得到我吗?”
“我能听到你,今天balabala……”
两次握手:
“喂,你听得到吗?”
“我听得到呀”“喂喂,你听得到吗?
“草,我听得到呀!!!!”
“你TM能不能听到我讲话啊!!喂!”
“……”
四次握手:
“喂,你听得到吗?”
“我听得到呀,你听得到我吗?”
“我能听到你,你能听到我吗?”
“……不想跟傻逼说话”
# 详情请看:https://www.zhihu.com/question/24853633
一句话概括就是:通过三次握手,A知道B能收能发,B知道A能收能发,通信连接至此建立。三次连接是保证可靠的最小握手次数,再多次握手也不能提高通信成功的概率,反而浪费资源。
<2>假设法科学版本解释(此处为截图,节选自 https://blog.****.net/qq_18425655/article/details/52163228):
三、TCP断开连接时的四次挥手
相信看了我上面的雅俗共赏的三次握手的解释,大家应该差不多能够理解了,那么关于断开连接的四次挥手又是指的什么呢?
下面我依然通过通俗说法和原理解释两种模式为大家呈现四次挥手的过程。
三次握手是客户端(以下记为A)和服务器(以下记为B)的三次灵魂的碰撞,同理,那么四次挥手便是客户端和服务器的四次“缠绵”。
1、直观理解版:
<1> A向B发起请求,表示A没有数据要发送了:A——>B;
<2> B向A发送信号,确认A的断开请求:B——>A;
<3> B向A发送信号,请求断开连接,表示B没有数据要发送了:B——>A;
<4> A向B发送确认信号,同意断开:A——>B。
2、原理分析版:
第一步,当主机A的应用程序通知TCP数据已经发送完毕时,TCP向主机B发送一个带有FIN附加标记的报文段(FIN表示英文finish)。
第二步,主机B收到这个FIN报文段之后,并不立即用FIN报文段回复主机A,而是先向主机A发送一个确认序号ACK,同时通知自己相应的应用程序:对方要求关闭连接(先发送ACK的目的是为了防止在这段时间内,对方重传FIN报文段)。
第三步,主机B的应用程序告诉TCP:我要彻底的关闭连接,TCP向主机A送一个FIN报文段。
第四步,主机A收到这个FIN报文段后,向主机B发送一个ACK表示连接彻底释放。
示意图如下:
3、看到这里,小伙伴们估计有以下几点疑问了:
疑问1:为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
疑问2:为什么连接的时候是三次“握手”,关闭的时候却需要四次“握手”?
不管是你们有这些疑问,我也困惑了,所以我查了很多资料后,总结了以下看法:
疑问1的解答:
按正常逻辑来理解,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须要设想网络是不可靠的(实际上确实不完全可靠),有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
疑问2的解答;
简单理解:挥手次数比握手多一次,是因为握手过程,通信只需要处理连接。而挥手过程,通信需要处理数据+连接。
准确理解:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
部分内容来自网络,源地址:https://www.jianshu.com/p/bbb6261cb13e和https://blog.****.net/qq_18425655/article/details/52163228