计算机网络——TCP释放连接的4次挥手

TCP连接释放过程比较复杂。

数据传输结束后,通信的双方都可释放连接。

TCP连接释放过程是四次挥手。

TCP报文段首部

上篇【计算机网络】TCP为什么需要3次握手

上篇中讲解了这四个字段的作用:

  • s e q seq seq序号
  • a c k ack ack确认号
  • S Y N SYN SYN同步位(释放连接不需要)
  • A C K ACK ACK确认位

因为在TCP释放连接,所以不需要用到同步位 S Y N SYN SYN 字段,而要用到一个新的字段:

  • F I N FIN FIN终止位

    ➢ 当终止位被置为 1 1 1 时,说明数据已发送完毕,请求释放连接

    ➢ 当终止位被置为 0 0 0 时,说明还有数据正在发送

image-20220619150538035

TCP建立连接

A A A 为客户端 ( C l i e n t ) (Client) (Client) B B B 为服务端 ( S e r v e r ) (Server) (Server)

在TCP释放连接的四次挥手中,我们只需要关注这两个标志位: F I N 、 A C K FIN、ACK FINACK

谁发出 F I N FIN FIN 的报文,就代表着它接下来不再发送任何数据,申请关闭连接通道。

A C K ACK ACK 报文就是一个回包的意思,用来确认对方发送连接的通道已经成功关闭了。

第一次挥手

image-20220619150020019

假设本次TCP连接, A A A 先把数据发完了:

  1. 终止位 F I N = 1 FIN=1 FIN=1 被置为 1 1 1,表示我在发起释放连接的请求。
  2. 序号 s e q = u seq=u seq=u,我最后给你发的数据序号从 u u u 开始(只要发数据 就一定会有序号)

第二次挥手

image-20220619151549039

B B B 同意了 A A A 的释放连接请求,所有数据都已接收完毕,此时会把服务端的接收缓存中剩下的所有数据都交给上层应用进程;

服务端接收窗口客户端发送窗口此时都不需要了。

  1. B B B 收到了 A A A 发的请求,并回复确认号 a c k = u + 1 ack=u+1 ack=u+1
  2. 有确认号,肯定有确认位 A C K = 1 ACK=1 ACK=1
  3. 本次传输自己的序号 s e q = v seq=v seq=v

此时,从 A A A B B B 这个方向的连接就释放了,TCP连接处于半关闭状态。

B B B 若发送数据, A A A 仍要接收,所以此时用到的是:服务端发送窗口客户端接受窗口

第三次挥手

image-20220619152603129

第三次请求还是 B B B A A A 发出的,在第二次请求与第三次请求中,这两个连续的请求包之间存在着隔断时间,因为对于 B B B 来说可能还有一些还未处理完的数据,此时需要一些异步等待时间;

我们抽象一下:
A:B啊,我不想玩了。
B:哦,你不想玩了啊,我知道了。
B:A啊,好吧,我也不玩了,拜拜。
A:好的,拜拜。

等服务端的数据都处理完成后,此时 B B B A A A 发送的请求只是单纯确认的请求:

  1. 终止位 F I N = 1 FIN=1 FIN=1,表示我的数据全部处理完了,我也申请释放连接。
  2. 确认号 a c k = u + 1 ack=u+1 ack=u+1,表示你发送的 u + 1 u+1 u+1 之前的数据我全部收到了。
  3. 确认位 A C K = 1 ACK=1 ACK=1
  4. 我本次请求的数据携带的序号字段为 s e q = w seq=w seq=w

第四次挥手

image-20220619153543725

A A A 收到了 B B B 的释放连接请求,并回复确认。

  1. 确认号 a c k = w + 1 ack=w+1 ack=w+1,表示你你发送的 w + 1 w+1 w+1 之前的数据我全部收到了。
  2. 确认位 A C K = 1 ACK=1 ACK=1
  3. 自己本次数据的序号字段 s e q = u + 1 seq=u+1 seq=u+1 对应你上次请求的确认号。

至此, A A A B B B 的连接释放完成。

四次挥手TCP连接的各个状态

  • E S T A B − L I S H E D ESTAB-LISHED ESTABLISHED:已确认连接状态
  • F I N − W A I T − 1 FIN-WAIT-1 FINWAIT1:主动关闭方的第一个等待状态(此时在等待 B B B 的确认)
  • F I N − W A I T − 2 FIN-WAIT-2 FINWAIT2:主动关闭方的第二个等待状态(此时在等待 B B B 处理未处理完的一些资源)
  • C L O S E − W A I T CLOSE-WAIT CLOSEWAIT:半关闭状态(对于被动关闭方 B B B 可能还需要处理内部的一些资源)
  • L A S T − A C K LAST-ACK LASTACK:等待最后一次确认状态
  • T I M E − W A I T TIME-WAIT TIMEWAIT:等待计时状态(等待计时器)
  • C L O S E D CLOSED CLOSED:关闭状态

image-20220619160202421

一个 F I N FIN FIN 对应一个 A C K ACK ACK

注意:只有主动关闭连接的,才有 T I M E − W A I T TIME-WAIT TIMEWAIT 状态。

TIME-WAIT状态解释

为什么会有这个状态(等待计时器)存在?

对于客户端 A A A 和服务端 B B B,都存在着一个超时计时器;

对于最后一次挥手, A A A 怎么知道 B B B 是否收到了呢?因为最后一次请求 B B B 不会给 A A A 回复,按以前的超时计时器来判断的话, A A A 会一直给 B B B N N N 个请求,直到 B B B A A A 回复确认请求,这显然是不可以的。

如果不设置超时计时器,万一对方真的没有收到呢?

所以此时就有一个 T I M E − W A I T TIME-WAIT TIMEWAIT(等待计时器)状态,为了确保我最后的一次请求 B B B 一定收到了。

假设我第四次请求丢失了,那么 B B B 的超时计时器发现后,会重新发送第三次请求,当 A A A 处在 T I M E − W A I T TIME-WAIT TIMEWAIT 状态时,又收到了第三次请求,则证明我发送的第四次请求丢失了, B B B 没有收到,此时 A A A 会重新发送第四次请求。

这样双方就都可以判断最后一次挥手有没有完成,判断依据是:在这 2 M S L 2MSL 2MSL 的等待时间中,对方都没有再给我发任何重复的数据包过来,那么我就可以认为对方收到了最后一次请求。

M S L ( M a x i m u m   S e g m e n t   L i f e t i m e ) MSL(Maximum\ Segment\ Lifetime) MSL(Maximum Segment Lifetime 是报文最大生存时间

A A A 必须等待 2 M S L 2MSL 2MSL 的时间:

  • 第一,为了保证 A A A 发送的最后一个 A C K ACK ACK 报文段能够到达 B B B

  • 第二,防止 “已失效的连接请求报文段” 出现在本连接中。

    A A A 在发送完最后一个 A C K ACK ACK 报文段后,再经过时间 2 M S L 2MSL 2MSL,就可以使本连接持续的时间内产生的所有报文段,都从网络中消失。

    这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。

更详细的分析可参考小林coding的TCP面试题

TIME_WAIT 过多有什么危害?如何优化 TIME_WAIT?

还是挺详细的。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐