TCP三握四挥?

143 阅读8分钟

TCP三握四挥?

即TCP三次握手、四次挥手。三次握手用于建立TCP连接,四次挥手用于销毁TCP连接

由于篇幅可能较长,建议反复斟酌

三次握手

  1. 客户端主动开启TCP连接,并发送一个TCP连接请求报文,这个报文有这些字段(注:TCP报文字段有好几个,这里主要讲的是建立连接时主要用到的字段),SYN = 1、seq = x(假设为x)。此时客户端的状态会变成SYN-SENT(同步已发送)

SYN = 1 表示这是一个TCP连接请求报文字段
seq = x 数据的初始序号,本身并不携带任何数据信息

  1. 服务端被动打开,然后进行监听。监听到客户端发送过来的请求连接报文后,会进行确认,并返回一个确认报文,并把状态变成SYN-RCVD(同步已接收)。该报文有这些字段SYN = 1,ACK = 1(注意,是大写的ACK),seq = y,ack = x+1。

SYN = 1,效果与第一步一样
ACK = 1,表示TCP连接确认请求的报文端,不能携带数据
ack = x+1,表示对请求连接的seq字段进行确认,并表示需要传输的下一个序号
seq = y,表示服务端数据的初始序号,同样不带任何数据

  1. 当客户端收到服务端的确认报文之后,会发送一个确认请求,并携带ACK = 1,seq = x+1,ack = y+1,并把状态变为ESTABKUSGED(连接已建立)

注:此时的seq可以携带数据了,字段的含义与上文所提及的效果是一样的

基于一堆文字给人的视觉震撼导致知识不如脑的情况下,我在这里简要概括一下每次发送报文时所发生的内容

  1. 客户端发起连接请求,此时客户端能够确认自身的发送能力是正常的
  2. 服务端接收到连接请求报文的时候,并返回一个确认连接的报文。此时服务端能够确认自身的发送能力以及接收能力是正常的。但此时服务端并不能确认客户端能不能收到自己的确认报文信息。
  3. 客户端收到服务端的确认连接请求后,确认了自身的接受能力是正常的,并且能接受到服务端所发来的报文。但此时服务端不能确定它自己能否收到客户端,所以需要客户端发送一个确认报文给它。
  4. 当服务端接收到客户端的确认报文后,服务端就知道了客户端能够收到它的消息,所以此时就可以愉快的传输数据了。

什么?还记不住?那举个例子吧

比如说A和B,分别表示客户端和服务端。

  • A拨打电话给B,B接听后,A说:能不能听见我说话?
  • B:听到了,你能听见我说话吗?
  • A:能听到,今晚五排!

A拨打电话给B,这一步就是连接请求报文
B接听后,听到A的话后,说自己能听到A说话,问A能不能听见B说话,这一步就是服务端发送确认连接报文
A听到B问他能不能听见他说话,就回他能听到,这一步就是对服务端的确认报文的确认,并且说今晚五排,这里代表的就是客户端在第三次握手的时候所携带信息

emmm...如果还是不能理解的话,多看看几遍就好了0v0

那然后就有个问题,为啥要三次,两次不行?这个问题其实上面的概括就可以回答了。

当然还有另外的回答。如果服务端没有收到客户端的确认连接报文的确认报文(可能丢失或网络阻塞),这必然会导致客户端的超时重传。

如果是丢失还好,那如果是由于网络阻塞,导致确认报文超过了定时器(超时重传)的时间,然后客户端发送新的连接确认报文,然后此时服务端收到了新的确认报文,然后传输数据。然后假设传输后,客户端关闭连接,而此时被阻塞的确认报文传到了服务端,服务端就会误以为客户端要连接了,就被动开启,又因为此时客户端已经关闭了,此时没有进行连接,那此时服务端就白白浪费了资源。所以需要三次握手。

什么?又因为字太多不想看?那就以上面打电话的例子来讲吧。

前面两步是一样的,主要看第三次

  • A:能听到,今晚五排! 诶,此时信号不好,然后A又说了一句,此时B听到了,然后后面吧啦吧啦后,挂断了。

然后假设过了几天,B的手机突然收到了A延迟的信息,以为A又打电话给他,就接听,然后A又一直不说话,B想着A这个叼毛打电话过来又不说话?然后B就一直等...

上面的假设仅用于解释说明,不要照应到现实中0v0

四次挥手

  1. 客户端方发送连接释放报文,该报文有这些字段,FIN = 1,ACK = 1,seq = u,ack = v,之后发送方状态变更为FIN-WAIT-1(终止等待1),此时也通知接收方自己已经没有数据要发送了。

FIN = 1,表示这是一个连接释放报文
ACK = 1,表示对之前的报文进行确定
seq = u,表示在此之前传输的数据序号为u
ack = v,表示对接收方传输过来的数据进行确认

  1. 服务端收到连接释放报文后,会返回一个普通的确认报文,所带字段有ACK = 1,seq = v ack = u+1;并进入CLOSE-WAIT状态(关闭等待)

这里的字段没什么好说的
这里为什么要有关闭等待状态?主要是服务端可能还有未处理完请求,可能还要发送数据给客户端,所以收到连接释放报文后,服务端还要等待一段时间。

  1. 当客户端收到服务端的普通确认报文后,就会进入FIN-WAIT-2(终止等待2),此时就等待服务端的连接释放报文。而服务端有可能把处理完的请求发送给客户端,所以这里还是可以进行数据传输的(单向)。如果没有要发送的数据,服务端就会发送连接释放报文,并进入LAST-ACK阶段(最后确认)。 这里的连接释放报文有这几个阶段,FIN = 1,ACK = 1,seq = w,ack = u+1;

主要关注这里的ack字段

  • ack = u + 1,这里是对上一个普通确认报文进行重复确认,毕竟客户端没有数据要发送了,同时也表明客户端确实是要关闭连接了。

为什么有这个LAST-ACK状态?主要是为了防止服务端连接释放报文丢失,需要进行超时重传。

  1. 当客户端收到服务端的连接释放报文后,会对该报文进行普通确认,然后进入TIME-WAIT(时间等待)状态。一般设为2MSL(4分钟,实际中30秒、1分钟都有)

为什么要要等待2MSL时间?

MSL,Maximum Segment Lifetime,最大报文段生存时间。即任何TCP报文在网络中存在的最大时长,如果超过这个时间,这个TCP报文就会被丢弃。

这里是考虑到 客户端 普通确认报文 丢失后,而服务端没有收到客户端的确认报文后,会进行超时重传连接释放报文。

这里有两种情况,

  • 客户端收到连接释放报文后,发送确认报文,但由于丢失导致服务端没有收到,服务端会认为客户端是没有收到,所以进行超时重传
  • 服务端发送的连接释放报文丢失,导致超时重传

由于过了一个MSL时间之后,报文就会丢失,而这里有两种情况,即第四次挥手的ACK包的最大生存时长(MSL)+服务端重传的FIN包的最大生存时长(MSL)=2MSL

为了确保远端TCP端能够收到它发出的终止连接请求的ACK应答包。

当客户端再次收到服务端连接释放报文后,发送ACK报文,并且重置2MSL的等待超时时间。

为什么要四握,三握不行?

如果客户端不经过2MSL时长的TIME_WAIT状态,发送ACK之后就立马关闭TCP链接,释放端口号和内存资源,会出现什么情况?
可能会出现服务端并没有收到ACK,然后重新发送第三次挥手的FIN包,而此时客户端又新建了到服务端的TCP连接,并且客户端使用的还是之前的端口号,那么网络中延迟到达的FIN包就会被这个新的TCP连接接接收到,这不是客户端希望接收到的数据,因此要等待2MSL的时长,确保网络中的FIN包全都不存在了,才关闭TCP连接,释放端口号和内存资源,这个时候客户端就可以重新使用这个端口号连接任何服务器,包括刚断开的这台服务器。

总结

TIME-WAIT设置为2MSL的原因

  • 确保被动关闭TCP连接的一端能收到第四次挥手的ACK
  • 避免上一次TCP连接的数据包影响到下一次的TCP连接。

参考文献

  1. 计算机网络(第八版)