TCP 为什么是三次握手?为什么四次挥手?

网上各路大佬都写了好多,看的我云里雾里,不过还是有些感触的

三次握手

对于举例最频繁的就是

1
2
3
A ->    在不   -> B
A <- 在,你在不 <- B
A -> 在 -> B

补充一下A为客户端,B为服务端,或者说这里说客户端服务端不太合适,应该叫主动发起端和被动接收端,两个服务之间都有向对方传输的能力,所以在TCP中,两个服务在建立连接的时候主动要求建立的叫客户端
虽然看上去通俗易懂,但是其实省略了关键细节
TCP为什么称之为可靠的传输协议,因为双方都在做一些检查,其中最重要的检查莫过于对双方序列号的校验
第一步握手,A主动发送同步请求SYN,B端处于listen状态,A在发送SYN请求的时候是会携带一个A生成序号ISN(identity serial number)
第二步握手,B在收到请求后记录A的ISN,然后会向A发送确认请求ACK,并且向A发送自己的同步请求SYN和序号ISN
第三步握手,A在收到B的同步请求记录B的ISN,然后向B发送已收到ACK

为什么不是两次或四次

两次的话只有B能确认A的序号,A在本该确认B的序号的第三步被省略了,所以肯定是不行的
四次的话其实已经没必要了,三次已经将足够需要确认的数据传输完毕,没有必要传输第四次了

为什么ACK数据包不要确认

ACK数据包本身就是一个确认另一端请求的数据包,试想一下,假如ACK需要确认,接收端收到ACK后向发送端确认ACK,发送端收到ACK后又向接收端确认ACK,是不是就无限循环下去了呢

四次挥手

其实关闭连接的四次挥手大致与三次握手相似,可以理解为将SYN包换成FIN包,并且将三次握手的第二步的SYN+ACK拆成了两步
所以就是

1
2
3
4
A ->  关了啊   -> B
A <- 好的 <- B
A <-那我也关了啊<- B
A -> 好的 -> B

那么这里就奇怪了,为什么服务端要把关闭+确认请求拆成两份呢,其实是这样子的
在三次握手中双发仅仅是建立连接,确认连接关系,没有数据传输,所以为了节省资源和带宽,将SYNACK同时发送了
而关闭连接不一样,其中一端(A)发送FIN请求关闭连接时,另一端(B)或许正在写入数据,那么就只能先响应ACK说我收到关闭请求了,将数据写完后再向A发送FIN,这时就可以正常关闭连接了

补充一张网图加深理解

第一步,FIN_WAIT_1很难遇到,因为下一步基本服务端都会秒回ACK
第二步,服务端秒回ACK后,服务端进入CLOSE_WAIT状态,在考虑是否还有数据要发送或者正在发送,客户端收到ACK相应进入FIN_WAIT_2,等待服务端的数据发送完后的FIN
第三步,服务端考虑完并完成传输后,会紧接着发送FIN包到客户端,进入LAST_ACK状态,客户端收到后进入TIME_WAIT状态
第四部,客户端向服务端发送ACK确认收到服务端的关闭请求,整个关闭流程结束