TCP建立连接的过程叫做握手,在建立可靠的数据传输通道后才会进行数据的传输,断开连接的过程叫做挥手。所谓的三次握手,4次挥手中的次数指的是在建立、断开连接过程中传送的报文段的次数。
在介绍握手和挥手之前我们需要先了解在这其中需要用的TCP里边的几个标志位:SYN(请求建立连接),seq(顺序号,作用是使得一个TCP接收端可丢弃重复的报文段),ACK(确认),ack(确认号),FIN(结束即请求断开连接)。
1. 三次握手
(1)过程解析:
客户端A主动向服务器B请求建立连接,在这之前AB都处于closed状态。在这个过程中客户端是主动请求建立连接,服务器端B是被动建立连接
- 第一次握手:A->B。SYN=1,seq=x,A进入同步已发送状态,B 进入监听状态
⚠️SYN=1表示请求建立连接,seq是序列号,值是随机产生。因为通信是相互的通过第一次握手确认了A的发能力和B的收能力是正确的 - 第二次握手:B<-A。分为两部分一部分是确认报文,对接收到A的建立连接消息的一个确认。即ACK=1,ack=x+1,还有一部分是向A发送建立连接的请求SYN=1,seq=y。B进入同步已确认状态
⚠️TCP规定SYN报文段即使不传送数据也要消耗一个序号,确认号ack是对A发送报文的确认,一般为seq的值+1,所以是x+1。B向A发送建立连接的请求所以SYN设置为1,在向A发送请求时候自己的序号是y。 - 第三次握手:A->B。ACK=1,ack=y+1,seq=x+1。AB进入已建立连接状态
(2)原因
写到这,到底为什么需要3次握手才能实现建立连接开辟资源呢?
因为连接是双向的。AB需要知道自己和对方的收发能力都是正常的才行。之所以采用三次握手是为了避免失效连接请求的情况。
通过上边的步骤解析,我们可以看到,通过第一次握手B知道A的发能力是正常的,通过第二次握手A知道B的收发能力和A自己的收发能力是正常的,而A虽然知道B的收发能力正常,但是B此时还不知道自己的发能力是不是正常的,所以需要第三次握手A对B给出确认,B知道自己的收发能力都正常,同时也知道A的收发能力都正常。
谢希仁版《计算机网络》中的例子:
"已失效的连接请求报文段”的产生在这样一种情况下:
client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。
本来这是一个早已失效的报文段,但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。
如果采用“两次握手”,那么只要server发出确认,新的连接就建立了。
由于现在client并没有发出建立连接的请求,因此不会对server的连接请求确认,也不会向server发送数据,但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。
2.四次挥手
(1)过程解析
在挥手之前ab双方在传数据,只要有任何一方数据传输完想要释放资源了都可以主动请求断开连接。假设A先传输完数据想要断开连接
- A->B FIN=1,seq=u
⚠️FIN=1表示请求断开连接,seq的值为最后传送的数据的序列号+1,A进入终止等待1状态 - B<-A B在接收到A发送过来的断开连接请求后要给A发送一个确认,表示我接收到你的断开连接请求了。A进入终止等待2状态,B进入关闭等待状态,B会通知高层应用进程A请求了断开连接,tcp处于半关闭状态,A向B发送数据的通道关闭了,但是B如果向A发送数据A依旧可以接收到。ACK=1,ack=u+1,seq=v
- B<-A 在第二次挥手之后,如果B有数据要发送给A依旧可以继续发送,在发送完之后B给A发消息,告诉A我发送完了,请求断开连接。B进入最后确认的状态。FIN=1,seq=w(w的值为发送的最后一个字节的序号+1),ACK=1,ack=u+1
⚠️:TCP规定,FIN字段即使不携带数据也要消耗一个序号,和SYN一样,但是ACK报文段携带数据就消耗一个序号,不携带就不消耗。 - A->B ACK=1,ack=u+1,seq=w+1
⚠️在最后一次握手之后,并没有立即断开连接,还需要等待2MSL时间(MSL:最长报文段寿命),A才会进入到closed状态。
(2)需要四次的原因
可能有的小可爱会有疑问,三次不就好了吗, 为什么需要4次呢。因为对于主动请求断开连接的一端A,它的数据肯定是传送完了的,而对于被请求断开连接的一端B,他可能还有数据没有传送完,在接收到断开连接请求时候,B无法决定是否马上断开连接,需要先和上层的应用沟通后才能确认,所以需要先回应A已经收到你的请求了,B在发送完数据之后才会发送断开连接的请求,这也就是第23次挥手存在的原因。