TCP四次挥手详解

article/2025/9/23 1:43:08

在开始之前可以先了解一下     TCP三次握手


TCP四次挥手过程和状态变迁

为什么挥手需要四次?

为什么TIME_WAIT等待的时间是2MSL?

等待2MSL的意义

TIME_WAIT状态过多有什么危害?

如何解决TIME_WAIT状态过多?


TCP四次挥手过程和状态变迁

 

在断开连接之前客户端和服务器都处于ESTABLISHED状态,双方都可以主动断开连接,以客户端主动断开连接为优。

第一次挥手:客户端打算断开连接,向服务器发送FIN报文(FIN标记位被设置为1,1表示为FIN,0表示不是),FIN报文中会指定一个序列号,之后客户端进入FIN_WAIT_1状态

也就是客户端发出连接释放报文段(FIN报文),指定序列号seq = u,主动关闭TCP连接,等待服务器的确认。

第二次挥手:服务器收到连接释放报文段(FIN报文)后,就向客户端发送ACK应答报文,以客户端的FIN报文的序列号 seq+1 作为ACK应答报文段的确认序列号ack = seq+1 = u + 1

接着服务器进入CLOSE_WAIT(等待关闭)状态,此时的TCP处于半关闭状态(下面会说什么是半关闭状态),客户端到服务器的连接释放。客户端收到来自服务器的ACK应答报文段后,进入FIN_WAIT_2状态。

第三次握手:服务器也打算断开连接,向客户端发送连接释放(FIN)报文段,之后服务器进入LASK_ACK(最后确认)状态,等待客户端的确认。

服务器的连接释放(FIN)报文段的FIN=1,ACK=1,序列号seq=m,确认序列号ack=u+1。

第四次握手:客户端收到来自服务器的连接释放(FIN)报文段后,会向服务器发送一个ACK应答报文段,以连接释放(FIN)报文段的确认序号 ack 作为ACK应答报文段的序列号 seq,以连接释放(FIN)报文段的序列号 seq+1作为确认序号ack。

之后客户端进入TIME_WAIT(时间等待)状态,服务器收到ACK应答报文段后,服务器就进入CLOSE(关闭)状态,到此服务器的连接已经完成关闭。

客户端处于TIME_WAIT状态时,此时的TCP还未释放掉,需要等待2MSL后,客户端才进入CLOSE状态


由客户端到服务器需要一个FIN和ACK,再由服务器到客户端需要一个FIN和ACK,因此通常被称为四次握手。

客户端和服务器都可以主动关闭连接,只有率先请求关闭的一方才会进入TIME_WAIT(时间等待状态)。

为什么挥手需要四次?

这是由于TCP的半关闭(half-close)造成的。半关闭是指:TCP提供了连接的一方在结束它的发送后还能接受来自另一端数据的能力。通俗来说,就是不能发送数据,但是还可以接受数据。

TCP不允许连接处于半打开状态时,就单向传输数据,因此完成三次握手后才可以传输数据(第三握手可以携带数据)。

当连接处于半关闭状态时,TCP是允许单向传输数据的,也就是说服务器此时仍然可以向客户端发送数据,等服务器不再发送数据时,才会发送FIN报文段,同意现在关闭连接。

这一特性是由于TCP双向通道互相独立所导致的,也使得关闭连接必须经过四次握手。

可能有些人会有疑惑:为什么中间的ACK和FIN不可以像三次握手那样合为一个报文段呢?

在socket网络编程中,执行close()方法会触发内核发送FIN报文。什么时候调用close()方法,这是由用户态决定的,假如服务器仍有大量数据等待处理,那么服务器会等数据处理完后,才调用close()方法,这个时间可能会很久,而ACK报文则是由系统内核来完成的,这个过程会很快。所以中间的ACK和FIN不能合为一个包。

为什么TIME_WAIT等待的时间是2MSL?

MSL(Maximum Segment LifeTime)是报文最大生成时间,它是任何报文在网络上存在的最长时间,超过这个时间的报文将被丢弃。

因为TCP协议是基于IP协议(位于IP协议的上一层),IP数据报中有限制其生存时间的TTL字段,是IP数据报可以经过的最大路由器的个数,每经过处理它的路由,TTL就会减一。TTL为 0 时还没有到达目的地的数据报将会被丢弃,同时发送 ICMP 报文通知源主机。

MSL的单位为时间,TTL的单位为跳转数。所以MSL应该大于等于TTL变为0的时间,以确保报文已被丢弃。

TIME_WAIT等待的2MSL时间,可以理解为数据报一来一回所需要的最大时间。

2MSL时间是从客户端接收到FIN后发送ACK开始计时的。如果在这个时间段内,服务器没有收到ACK应答报文段,会重发FIN报文段,如果客户端收到了FIN报文段,那么2MSL的时间将会被重置。如果在2MSL时间段内,没有收到任何数据报,客户端则会进入CLOSE状态。

等待2MSL的意义

1.保证客户端最后发送的ACK能够到达服务器,帮助其正常关闭。

由于这个ACK报文段可能会丢失,使得处于LAST_ACK状态的服务器得不到对已发送FIN报文段的确认,从而会触发超时重传。服务器会重发FIN报文段,客户端能保证在2MSL时间内收到来自服务器的重传FIN报文段,从而客户端重新发送ACK应答报文段,并重置2MSL计数。

假如客户端不等待2MSL就之间进入CLOSE状态,那么服务器会一直处于LAST_ACK状态。

当客户端发起建立SYN报文段请求建立新的连接时,服务端会发送RST报文段给客户端,连接建立的过程就会被终止。

2.防止已失效的连接请求报文段出现在本连接中。

TIME_WAIT等待的2MSL时间,确保本连接内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。

TIME_WAIT状态过多有什么危害?

只有主动发起断开请求的一方才会进入TIME_WAIT状态!

1.占用系统资源

2.socket的TIME_WAIT状态结束之前,该socket占用的端口号将一直无法释放。如果服务器TIME_WAIT状态过多,占满了所有端口资源,则会导致无法创建新的连接。

如何解决TIME_WAIT状态过多?

最好的办法是尽量让客户端主动断开连接,除非遇到一些异常情况,如客户端协议错误、客户端超时等。

打开系统的TIME_WAIT重用和快速回收。

在Linux系统可以修改以下参数:

        1.打开TCP对时间戳的支持,保持服务器与客户端时间同步 

net.ipv4.tcp_timestamps=1(默认即为 1)

        2.修改net.ipv4.tcp_tw_reuse = 1,允许对处于TIME_WAIT的socket用于建立新的连接

net.ipv4.tcp_tw_reuse = 1 (默认为0)

修改TIME_WAIT连接状态的上限值,超过上限值,处于TIME_WAIT状态的socket将立刻被清除并打印警告信息。

net.ipv4.tcp_max_tw_buckets = 18000,表示系统同时保持处于TIME_WAIT状态的socket的最大数量,默认为18000。

可修改为更小值。

net.ipv4.tcp_max_tw_buckets = 6666

还有一个是修改短连接为长连接的方式(目前没有学到)。


http://chatgpt.dhexx.cn/article/oRI3al2Q.shtml

相关文章

C++ map遍历

C map遍历 #include <iostream> #include <map>using namespace std;int main() {map<int, int> _map;_map[0] 1;_map[1] 2;_map[10] 10;map<int, int>::iterator iter;iter _map.begin();while(iter ! _map.end()) {cout << iter->firs…

C++ map遍历(简单易记忆)

C中map遍历有两种方法&#xff1a; 第一种&#xff0c;使用迭代器&#xff0c;while循环 #include <iostream> #include <map> using namespace std; int main() {map<int,int> p;p[0] 1;p[1] 2;p[3] 4;map<int,int>::iterator it p.begin();whi…

Java中Map的4种遍历方式

原标题&#xff1a;Java中Map的4种遍历方式 第一种方式&#xff1a;这是平常用的最多也最可取的一种遍历方式。 for (Map.Entry entry : map.entrySet()) { System.out.println(“key” entry.getKey() “,value” entry.getValue()); 第二种方式&#xff1a;如果只需要…

HashMap的几种遍历方式及循环删除

目录 1. 前言2. HashMap 的遍历方式2.1. 迭代器 EntrySet2.2. 迭代器 KeySet2.3. ForEach EntrySet2.4. ForEach KeySet2.5. Lambda 表达式2.6. Streams API 3. 循环删除3.1. 迭代器 Iterator 方式3.2. ForEach 循环方式3.3. Lambda 表达式3.3.1. Lambda 删除的正确方式 3.4. S…

Map遍历四种方式及其效率

目录 1、Map介绍 2、Map数据结构及扩容 2.1、数组&#xff1a;寻址容易&#xff0c;插入和删除元素困难 2.2、链表&#xff1a;寻址困难&#xff0c;插入和删除元素容易 2.3、Map数组长度默认16&#xff0c;扩容负载因子为0.75 3、Map遍历4种方式及其效率 3.1、方式一&a…

前端map循环遍历使用

map定义 Array.map() ⽅法返回⼀个新数组&#xff0c;数组中的元素为原始数组元素调⽤函数处理后的值&#xff0c;同时不会改变原来的数组 var newArra[1,3,6,10,44]; var newArraysnewArra.map((index) > { return index*index }) console.log(newArra); //[1,3,6,10,44]…

map forEach for in 循环遍历

1.map遍历数组对象 var map [{ key : "百度", value : "李彦宏" },{key : "阿里巴巴", value : "马云" },]; for (var key in map) { console.log(map[key]); } 2.forEach遍历数组 forEach()方法需要一个函数作为参数&…

Map的循环遍历,修改,删除

预制数据 Map<String, String> map new HashMap<>();map.put("aaa","123");map.put("bbb","123");map.put("CCC","123"); 只循环key ---> map.keyset() for (String key : map.keySet()) {Syst…

Java遍历Map五种方法

一、Map集合遍历日常开发最常使用&#xff0c;简单总结五种方法差异。 ①、IteratorentrySet写法【推荐JDK8以下】&#xff0c;Map.Entry是Map接口的内部接口&#xff0c;获取迭代器&#xff0c;然后依次取出每个迭代器里面的Map.Entry Iterator<Map.Entry<Integer,Strin…

443端口被占用怎么办

前段时间配置SDN的时候装了虚拟机&#xff0c;然后最近打开Steam插件访问社区的时候发现跳出错误&#xff0c;443端口被占用&#xff0c;一脸懵逼&#xff0c;后来查找资料才发现原来是虚拟机的vmware-hosted进程占用了443端口 可以通过右键计算机——服务和应用程序——服务—…

当443端口被占用时如何解决?

有时候我们的一些软件需要443端口才能运行&#xff0c;但是443被占用了&#xff0c;应当怎么结束呢&#xff1f; 1&#xff0c;打开CMD&#xff0c;输入netstat -ano回车&#xff0c;如图&#xff1a; 可以看到某程序正在占用443端口&#xff08;左边一列0.0.0.0:443,0.0.0.0代…

steamcom启动服务:443端口被占用,请关闭占用该端口的进程后再点击启动服务!

steamcom启动服务&#xff1a;443端口被占用&#xff0c;请关闭占用该端口的进程后再点击启动服务! 最近想玩玩游戏放松放松&#xff0c;但是steam有点问题&#xff0c;于是下了个插件steamcom,但在启动服务时出现了错误。 过程结果及解决方案 1、下载压缩文件并解压 2、运…

解除445端口的占用

有很多时候,我们测试的时候,会需要用到445端口。而windows默认该端口是开放的,那么我们如何关闭该端口的占用状态呢? 不是通过防火墙阻止445端口的连接来关闭,这种是阻止外部连接,但是本地445端口还是开放的。 我们这里讲的是关闭占用445端口的服务! 关闭Server服务 …

steamcommunity本地反代443端口/80端口被占用解决办法

参考了这两篇文章&#xff1a; https://www.cnblogs.com/chihirotan/p/5785339.html https://blog.csdn.net/mituan1234567/article/details/51085580 太长不看版&#xff1a; 我的电脑最近几天装了VMware&#xff0c;VMware占用了443端口导致steamcommunity无法启动。解决办…

端口被占用但实际端口没被占用

【问题描述】 启动nacos、sentinel时报端口被占用&#xff0c;使用netstat -aon|findstr 8080查找端口使用情况却发现该端口并没有被使用 【问题解决】 原出处&#xff1a;win10系统遇到了一个十分诡异的情况&#xff0c;端口明明没被占用却老是提示端口已占用-CSDN社区 原…

端口被占用如何关闭

在开发的时候有些时候会发现端口冲突的问题&#xff0c;比如最常使用的8080端口为例&#xff1a; 那么如何查询那个进程使用该端口并进行关闭呢&#xff1f; 首先进入命令行窗口输入下方的命令查看所有的端口占用情况 >netstat -ano上面一步不是必须的&#xff0c;然后输入…

VMWare Workstation 443端口被占用

问题说明及检测&#xff1a; 今天安装svn的时候提示端口占用&#xff0c; cmd –>> netstat -aon | findstr “443” 查看到进程的pid为3312 ctrl shift esc 选择服务&#xff0c;查看到进程名&#xff08;点下PID可排序&#xff09; 这个问题是处在VMware上&…

443端口占用问题

起因 科学上网有问题 呗计算机积极拒绝了 俺也不晓得是啥问题&#xff0c;就先去排查了一些问题 下面是两个链接 给我很大帮助 cmd来查看和排出433是谁在占用 VMware占用443的解决路径 查看433占用 使用cmd netstat -ano|findstr “443” 得到如下结果 然后使用 tasklist|…

VMware占用443端口冲突的解决办法

http://www.pc6.com/infoview/Article_70640.html 今天安装了一个VMware Workstation&#xff0c;发现XAMPP的Apache就启动不了。看了一下错误日志&#xff0c;似乎是VMware Workstation占用了443端口导致冲突引起的。查看了一下&#xff0c;原来VMware Workstation有个共享虚拟…

window 服务器443端口占用,443和80端口被占用win10如何解决_443和80端口被占用win10怎么处理...

我们要知道&#xff0c;443端口即网页浏览端口&#xff0c;80端口为HTTP即超文本传输协议开放的&#xff0c;这是用来保护win10系统的正常运行&#xff0c;但是病毒也能通过端口进入系统&#xff0c;最近有用户发现win10系统443和80端口被占用了&#xff0c;对此&#xff0c;小…