电脑之家 - 专业计算机基础知识与电脑技术学习网站
分类导航

路由器|交换机|网络协议|网络知识|

服务器之家 - 电脑之家 - 网络技术 - 网络协议 - 四次挥手,TCP连接的关闭

四次挥手,TCP连接的关闭

2021-10-28 22:14小菜学编程fasionchan 网络协议

我们退出 telnet 命令后,TCP 将关闭连接。于此同时,我们通过 tcpdump 也观察到 TCP 关闭连接的通信过程。本节,我们继续深入研究 TCP 关闭连接的通信细节。

四次挥手,TCP连接的关闭

本文转载自微信公众号「小菜学编程」,作者fasionchan。转载本文请联系小菜学编程公众号。

上一小节,我们通过一个实验,深入地研究了 TCP 三次握手建立连接的过程。

我们退出 telnet 命令后,TCP 将关闭连接。于此同时,我们通过 tcpdump 也观察到 TCP 关闭连接的通信过程。本节,我们继续深入研究 TCP 关闭连接的通信细节。

上节实验中的通信过程,已经被抓包并保存起来,我们直接用 tcpdump 命令将其打开( tcp.pcap ):

  1. root@client[~]➜tcpdump-nrtcp.pcap
  2. readingfromfiletcp.pcap,link-typeLINUX_SLL(Linuxcookedv1)
  3. 17:31:57.624391ARP,Requestwho-has10.0.0.2tell10.0.0.3,length28
  4. 17:31:57.624439ARP,Reply10.0.0.2is-at0e:bd:60:1c:69:9d,length28
  5. 17:31:57.624450IP10.0.0.3.55692>10.0.0.2.22:Flags[S],seq386101196,win29200,options[mss1460,sackOK,TSval811948031ecr0,nop,wscale7],length0
  6. 17:31:57.624495IP10.0.0.2.22>10.0.0.3.55692:Flags[S.],seq1155103769,ack386101197,win28960,options[mss1460,sackOK,TSval3541712191ecr811948031,nop,wscale7],length0
  7. 17:31:57.624522IP10.0.0.3.55692>10.0.0.2.22:Flags[.],ack1,win229,options[nop,nop,TSval811948031ecr3541712191],length0
  8. 17:31:57.635739IP10.0.0.2.22>10.0.0.3.55692:Flags[P.],seq1:42,ack1,win227,options[nop,nop,TSval3541712202ecr811948031],length41
  9. 17:31:57.635778IP10.0.0.3.55692>10.0.0.2.22:Flags[.],ack42,win229,options[nop,nop,TSval811948042ecr3541712202],length0
  10. 17:31:59.808411IP10.0.0.3.55692>10.0.0.2.22:Flags[F.],seq1,ack42,win229,options[nop,nop,TSval811950215ecr3541712202],length0
  11. 17:31:59.809175IP10.0.0.2.22>10.0.0.3.55692:Flags[.],ack2,win227,options[nop,nop,TSval3541714376ecr811950215],length0
  12. 17:31:59.809464IP10.0.0.2.22>10.0.0.3.55692:Flags[F.],seq42,ack2,win227,options[nop,nop,TSval3541714376ecr811950215],length0
  13. 17:31:59.809483IP10.0.0.3.55692>10.0.0.2.22:Flags[.],ack43,win229,options[nop,nop,TSval811950216ecr3541714376],length0

很显然,最后四个包就是四次挥手关闭连接的过程:

四次挥手,TCP连接的关闭

当我们按下 Ctrl-D 退出 telnet 命令时,客户机向服务器发出一个 FIN 包。这是一个设置了 FIN 标志位的 TCP 分组,它告诉服务器,客户机这端的数据已经发完,准备关闭连接:

四次挥手,TCP连接的关闭

服务器收到 FIN 包后,将回复一个 ACK 进行确认。注意到,确认号在 FIN 包序号的基础上加一,因为 FIN 也要占用一个序号,跟 SYN 一样。

于此同时,服务器将连接读端关闭的情况通知上层应用程序—— SSH 服务进程。至此,TCP 连接中从客户机到服务器的传输方向已经关闭,连接处于 半关闭 状态。

四次挥手,TCP连接的关闭

上图灰色部分就是其中已关闭的传输方向,它对客户机来说是 写端 ,对服务器来说是 读端 。另一个方向的数据传输仍可正常进行,因此服务器可以继续发送数据(写端),客户机也可以接收服务器发来的数据(读端)。

SSH 服务进程获悉客户机关闭连接后,便准备结束服务并关闭连接。如果这时它还有数据没发完,仍可通过半开连接发往客户机。等所有数据都发送完毕,服务器同样发送 FIN 分组,告诉客户端连接关闭。

一个 TCP 连接包含两个方向的传输通道,因此需要两对 FIN/ACK 分组,各自负责关闭对应的方向。因此,这两对 FIN/ACK 交互也被形象地称为 四次挥手 。

状态变迁

TCP 建立连接需要三次握手,关闭连接需要四次挥手,步骤相对繁琐。这意味着一个 TCP 连接应该有很多中间状态,接下来我们深入研究一下:

四次挥手,TCP连接的关闭

上图是 TCP 连接全生命周期时序图,左边是客户端的时间轴,右边是服务端的时间轴。时间轴上的不同颜色,则分别表示客户端和服务端连接所处的状态:

  1. 客户端发出 SYN 分组,连接进入 SYN_SENT 状态;
  2. 服务端收到客户端发来的 SYN 分组,它回复 SYN/ACK 分组,连接进入 SYN_RECV 状态;
  3. 客户端收到服务器的 SYN/ACK 分组,它回复 ACK 分组,连接进入 ESTABLISHED 状态;
  4. 服务器收到客户端的 ACK 分组,服务端连接也进入 ESTABLISHED 状态;
  5. 当连接处于 ESTABLISHED 状态时,客户端和服务端可以互相传输数据;
  6. 时序图中间的数据分组及其后的 ACK 分组,为实验中 SSH 服务向客户机返回自己的版本信息(这部分数据被 telnet 命令直接输出到屏幕中);
  7. 客户端准备退出时,它通过 FIN 分组通知服务端,连接进入 FIN_WAIT1 状态;
  8. 服务器收到客户端发来的 FIN 分组,它回复 ACK 分组进行确认,连接进入 CLOSE_WAIT 状态;
  9. 客户端收到服务器发来的 ACK 分组,连接进入 FIN_WAIT2 状态;
  10. 这时连接处于半关闭状态,服务器仍可以向客户端发送数据;
  11. 服务器发完剩余数据后,向客户端发送 FIN 分组,通知客户端关闭连接,服务端连接便进入 LAST_ACK 状态;
  12. 客户端收到服务器发来的 FIN 分组,回复 ACK 分组进行确认,客户端连接进行 TIME_WAIT 状态;
  13. 服务端收到 ACK 分组后,连接彻底关闭;
  14. 由于最后一个 ACK 分组可能会丢,客户端必须在 TIME_WAIT 状态等待一段时间,以便对服务器重传的 FIN 分组进行确认;

至此,我们可以得到一个完整的 TCP 状态变迁图:

四次挥手,TCP连接的关闭

TCP 主动连接方(客户端)和被动连接方(服务端)的状态变迁路径是不一样的:图中的绿色路径是客户端正常情况的状态变迁路径;而红色路径是服务端正常情况下的变迁路径。从图中可以看到,主动关闭方的状态变迁,也比被动关闭方要复杂得多。

根据 TCP/IP详解 的介绍,TCP 协议也支持从服务端发起建立连接。但由于这种实现实际上非常罕见,这里就不作深入介绍了。

状态变迁是 TCP 协议的一个重要知识点,特别是对 TIME_WAIT 状态的理解,在后端技术面试中经常考察。

TIME_WAIT 状态

TCP 主动关闭方最终会进入 TIME_WAIT 状态,并维持 2MSL 时长,为什么呢?

四次挥手,TCP连接的关闭

如上图,假设四次挥手中最后一个 ACK 分组在网络中丢失了,会发生什么事情呢?这时被动关闭的服务端会重传 FIN 分组。因此主动关闭方不能直接关闭,而应该在 TIME_WAIT 状态下维持一段时间,以便向重传的 FIN 分组回复 ACK 分组。否则对端仍会重传 FIN 分组,并在重试若干次后放弃,这时连接只能异常关闭。

另一方面,一个 TCP 连接由通信双方的 IP 地址和端口组成的四元组唯一确定。如果主动关闭方不在 TIME_WAIT 状态下等待一段时间,而是快速关闭释放资源,又会发生什么事情呢?这时原来的四元组有可能被新的连接复用,而旧连接重传的 FIN 分组可能因网络原因延迟到达,最终对新连接产生冲突干扰。

那么,为什么是维持 TIME_WAIT 状态 2MSL 时长呢?

MSL 是最大分组寿命( maximum segment lifetime )的简称,即一个 TCP 分组被丢弃前能够在网络中存在的最长时间。这个时间肯定是有限的,因为负责传输 TCP 分组的 IP 包中有限制存活时间的 TTL 字段。由于 IP 包对存活时间的限制是基于跳数的,因此两者不对等。不同的网络协议栈实现,MSL的取值也不尽相同:30秒、1分钟或2分钟都有。

将 TIME_WAIT 状态维持 2MSL 时长是出于这样的考虑:

假设最后一个 ACK 分组刚好在存活时间耗尽前到达对端主机,这时已经过了 MSL 时间。对端收到 ACK 后,就会立即关闭连接,不可能再发送 FIN 分组。但如果对端在收到 ACK 前刚刚重传了 FIN 分组,就必须再经过 MSL 时间才能保证 FIN 分组从网络中消失。因此,连接必须维持 TIME_WAIT 状态 2MSL 时间后才能释放,否则就可能对潜在的新连接造成干扰。

你可能会问,如果最后一个 ACK 分组丢了,对端不是还会继续重传 FIN 分组吗?不用再继续等待 FIN 失效吗?

是的,对端肯定会重传 FIN 分组,而且通常 很快 就开始重传。MSL 一般是几十秒,而网络往返时间要小得多,通常只是毫秒级,TCP 重传时间数量级也是差不多。因此,在 MSL 时间内,TCP 可以重传 FIN 分组好几次了!如果其中有一个 FIN 分组可以到达,TCP 会重置定时器,将 TIME_WAIT 状态再维持 2MSL 时长。如果几个 FIN 分组都丢了,那再等下去也没啥意义了!

  • 如果最后一个 ACK 分组可以到达对端,最多只需要等待 2MSL 时间即可保证网络中没有对端重传的 FIN 分组;
  • 如果最后一个 ACK 分组丢失了,对端在 MSL 内已经重传 好多次 了;
    • 如果重传的 FIN 分组有一个可以到达本端,TCP 回复 ACK 后会重置定时器在 TIME_WAIT 继续等待 2MSL 时长;
    • 如果重传的 FIN 分组都丢了,说明网络质量很差,再等下去也没有意义了;

因此,主动关闭方收到对端 FIN 分组后,必须在 TIME_WAIT 状态等待 2MSL ,才能释放连接。这样既保证对重传 FIN 分组的回复,又保证重传的 FIN 分组从网络中消失,不会对复用四元组的新连接造成冲突干扰。

主动关闭方一般是客户端,并发一般不高,因此 TIME_WAIT 状态基本不会造成任何影响。如果一个高并发服务(比如 Web 服务)存在大量短连接,则可能留下很多 TIME_WAIT 状态的连接。由于 TIME_WAIT 状态套接字无法立即回收,它们将占用大量的系统资源,对服务的性能造成严重影响。

这时,系统管理员可以选择系统的 2MSL 时长适当调短,加快 TIME_WAIT 连接的清理速度。此外,在 Linux 系统中,可以开启 tcp_tw_recycle 和 tcp_tw_reuse 内核选项,以复用 TIME_WAIT 状态的套接字。这些属于 TCP 和系统调优的范畴,后续有机会再专门展开介绍。

原文链接:https://mp.weixin.qq.com/s/NjjMzzktGGnkdI3mzjRkog

延伸 · 阅读

精彩推荐
  • 网络协议三分钟教你读懂通信协议

    三分钟教你读懂通信协议

    协议到底是什么?为什么大家都在强调协议的重要性?学习协议有哪些注意事项?今天小编就给大家简单介绍下相关内容。...

    中兴文档9972021-10-27
  • 网络协议一文读懂 https 底层原理

    一文读懂 https 底层原理

    既然https协议本质只是http上加了安全层,本文就主要将安全层是怎么实现的。当然要靠加密。加密又分成对称加密和非对称加密。...

    Java知音11462021-12-26
  • 网络协议5分钟看懂互联网安全协议IPSec

    5分钟看懂互联网安全协议IPSec

    通信双方需要一个真正在IP层提供安全性的方法,保证发送和接收的数据是安全的,IPSec(Internet Protocol Security,互联网安全协议)做到了。...

    中兴文档9342021-11-01
  • 网络协议从一次线上问题说起,详解 TCP 半连接队列、全连接队列

    从一次线上问题说起,详解 TCP 半连接队列、全连接队列

    某次大促值班 ing,对系统稳定性有着充分信心、心态稳如老狗的笔者突然收到上游反馈有万分几的概率请求我们 endpoint 会出现 Connection timeout 。...

    云巅论剑11612021-10-28
  • 网络协议HTTP缓存协议实战

    HTTP缓存协议实战

    缓存,又称作Cache,我们把临时存储数据的地方叫做缓存池,缓存池里面放的数据就叫做缓存,本文就以实战的形式为大家介绍HTTP缓存协议。...

    vivo互联网技术6942022-03-10
  • 网络协议为什么叫 HTTP/2 ,而不是 HTTP/2.0 ?

    为什么叫 HTTP/2 ,而不是 HTTP/2.0 ?

    互联网时代,足不出户,点点鼠标就可以轻松了解外面的世界变化,这一切得益于网络传输数据。我们都知道网络有7层模型,从底层到上层依次是:物理层...

    微观技术4842021-11-01
  • 网络协议四次挥手,TCP连接的关闭

    四次挥手,TCP连接的关闭

    我们退出 telnet 命令后,TCP 将关闭连接。于此同时,我们通过 tcpdump 也观察到 TCP 关闭连接的通信过程。本节,我们继续深入研究 TCP 关闭连接的通信细节。...

    小菜学编程9942021-10-28
  • 网络协议OAuth2.0协议扩展——OIDC认证协议

    OAuth2.0协议扩展——OIDC认证协议

    客户端无法认定资源拥有者就是正确的拥护者,虽然市面上的OAuth 2.0能够保证授权的安全性,但是OAuth 2.0本身并没有对用户认证提供明确的规范。...

    码农小胖哥4952021-08-02