socket close和shutdown的区别,TIME_WAIT和CLOSE_WAIT

TCP主动关闭连接
 
appl: close(), --> FIN FIN_WAIT_1 //主动关闭socket方,调用close关闭socket,发FIN
               <-- ACK FIN_WAIT_2 //对方操作系统的TCP层,给ACK响应。然后给FIN
               <-- FIN
               --> ACK "TIME_WAIT" -- 2MSL timeout -->CLOSED //TIME_WAIT,防止ACK没有给到对方。
 
TCP被动关闭连接
 
               <-- FIN "CLOSE_WAIT" //被动方,收到对方的FIN,处于CLOSE_WAIT状态
               --> ACK //被动方的TCP层,给ACK响应
app2: close(), --> FIN LAST_ACK //被动方调用close,从CLOSE_WAIT转到LAST_ACK 不调close,将一直在CLOSE_WAIT状态。
               <-- ACK --> CLOSED tcp是全双工:: 因此close()关闭读写。 shutdown()可以选择关闭读或写。 time_wait的时间会非常长,因此server尽量减少主动关闭连接。
 
 
int close(int sockfd); int shutdown(int sockfd, int howto); // howto: SHUT_RD, SHUT_WR, SHUT_RDWR
shutdown()函数的两个作用:
close()将描述字的引用计数减1,当引用计数为0时,才关闭socket。
如fork()模式中,父进程在accept()返回后,fork()子进程,由子进程处理connfd,而父进程将close(connfd);但此时父进程的close()并不引发FIN。
 

shutdown()则不管socket的引用计数,直接发生FIN。
shutdown()可控制read/write两个方向的管道。
SHUT_RD shutdown(sockfd, SHUT_RD);后,来自对端的数据都被确认,然后悄然丢弃。 SHUT_WR half close状态。
 
close()引发的4次交互:(这里的close是client发起的)
 
client server
FIN_WAIT_1 ---- FIN M ------> (Server端操作系统的TCP层响应ACK包)
<---- ACK M+1---- CLOSE_WAIT FIN_WAIT_2 (这里必须调用close,才能从CLOSE_WAIT到LAST_ACK)
<------ FIN N ----- LAST_ACK TIME_WAIT (TIME_WAIT有一个重要的作用就是防止最后一个ACK丢失)
------- ACK N+1 ----------> CLOSE
TIME_WAIT 是主动关闭链接时形成的,等待2MSL时间,约4分钟。

         主要是防止最后一个ACK丢失。  由于time_wait的时间会非常长,因此server端应尽量减少主动关闭连接

 

CLOSE_WAIT是被动关闭链接是形成的 ,

        按状态机,我方收到FIN,则由TCP实现发送ACK,因此进入CLOSE_WAIT状态。

        但如果我方不执行close(),就不能由CLOSE_WAIT迁移到LAST_ACK,则系统中会存在很多CLOSE_WAIT状态的连接。

此时,可能是系统忙于处理读、写操作,而未将已收到FIN的连接,进行close。此时,recv/read已收到FIN的连接socket,会返回0。

 

大量TIME_WAIT和CLOSE_WAIT的存在,会产生怎样的影响?

        内核维护更多的状态。收到ip包,做hash运算,hlist冲突的概率更大。

 

1. 首先明确下什么是2MSL: TCP四次挥手断开连接时,主动断开连接的一方(这里我们称为客户端A)在收到对端(这里我们称为服务端B)发送的FIN包后,会立马发送ACK响应包并等待一段时间以确保自己发送的ACK包能够成功通过网络传输到达服务端B端,从而帮助B端正常断开连接(B服务端只有收到自己发出的FIN包对应的ACK包后,才能正常释放资源断开连接),这一等待时间的时长为2MSL,是从客户端A发出ACK包开始计算的,如果A在发送完ACK包后又收到了B端发送的新的FIN包,则会再次发送新的ACK包并重新计时(B端可能会因为超时或丢包等各种原因重新发送FIN包);
2. 其次明确下什么是MSL:MSL 即 Maximum Segment Lifetime,它是任何 TCP segment 在网络上存在的最长时间,超过这个时间的 TCP 报文就会被丢弃,RFC793定义了MSL为2分钟,但这完全是从工程上来考虑的,对于现在的网络,不同操作系统的TCP实现,可以根据具体网络情况配置使用更小的MSL;

3. 再次明确下为什么TCP第四次挥手需要等待2MSL:客户端A等待2MSL可以确保客户端A和服务端B之间的数据包可以完成一个完整的来回的传输即 round trip,所以如果A先前发送的ACK包因为某些原因在网络上丢失了,服务端B在超时没有收到客户端A的ACK包后会重新发送FIN包,2MSL的等待时间能够确保客户端A收到服务端B发送的新的FIN包以发送新的ACK包并重新计时;

4. 最后说下如何在LINUX操作系统中查看和配置MSL: 其实在LINUX操作系统中并没有直接配置 MSL 而是配置了 tcp_fin_timeout,由于 tcp_fin_timeout=2MSL,所以我们可以查看tcp_fin_timeout并据此推断MSL: 可以通过命令 sysctl net.ipv4.tcp_fin_timeout 查看 tcp_fin_timeout,可以通过命令 sysctl -w net.ipv4.tcp_fin_timeout=30 修改 tcp_fin_timeout;

简单概括下,因为网络是不可靠的,数据包在传输过程中可能丢失可能超时可能乱序,所以TCP为了在逻辑的虚拟的连接的基础上提供可靠性,在四次挥手断开连接时主动断开连接的一方需要2MSL的等待时间(当然三次握手和四次挥手,以及连接过程中的确认/累计确认/选择确认等机制,也都是这个原因)

 

 

TCP四次挥手也遵循相似的套路。

主动断开的一侧为A,被动断开的一侧为B。

第一个消息:A发FIN

第二个消息:B回复ACK

第三个消息:B发出FIN

此时此刻:B单方面认为自己与A达成了共识,即双方都同意关闭连接。

此时,B能释放这个TCP连接占用的内存资源吗?不能,B一定要确保A收到自己的ACK、FIN。

所以B需要静静地等待A的第四个消息的到来:

第四个消息:A发出ACK,用于确认收到B的FIN

当B接收到此消息,即认为双方达成了同步:双方都知道连接可以释放了,此时B可以安全地释放此TCP连接所占用的内存资源、端口号。

所以被动关闭的B无需任何wait time,直接释放资源。

但,A并不知道B是否接到自己的ACK,A是这么想的:

1)如果B没有收到自己的ACK,会超时重传FiN

那么A再次接到重传的FIN,会再次发送ACK

2)如果B收到自己的ACK,也不会再发任何消息,包括ACK

无论是1还是2,A都需要等待,要取这两种情况等待时间的最大值,以应对最坏的情况发生,这个最坏情况是:

去向ACK消息最大存活时间(MSL) + 来向FIN消息的最大存活时间(MSL)。

这恰恰就是2MSL( Maximum Segment Life)。

等待2MSL时间,A就可以放心地释放TCP占用的资源、端口号,此时可以使用该端口号连接任何服务器。

为何一定要等2MSL?

如果不等,释放的端口可能会重连刚断开的服务器端口,这样依然存活在网络里的老的TCP报文可能与新TCP连接报文冲突,造成数据冲突,

为避免此种情况,需要耐心等待网络老的TCP连接的活跃报文全部死翘翘,2MSL时间可以满足这个需求(尽管非常保守)!

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/800936.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

七、Scrapy框架-案例1

1. 豆瓣民谣Top排名爬取 1.1 构建scrapy项目安装Scrapy库 pip install scrapy创建Scrapy项目 通过cmd进入命令窗口,执行命令scrapy startproject xxxx (xxxx为scrapy项目名),创建scrapy项目。 scrapy startproject douban_spider2024创建爬虫项目 执行scrapy genspider xxx(…

帝国cms备份的数据库文件夹

帝国CMS的数据库路径通常位于帝国CMS安装目录下的 data 目录中。以下是几种常见的查找方法: 查看 config.php 文件定位 config.php 文件:打开帝国CMS安装目录下的 e/config/config.php 文件(对于帝国CMS 7.0及以后的版本)。 对于帝国CMS 7.0之前的版本,打开 e/class/confi…

帝国cms所有数据库字段说明

帝国CMS(Empire CMS)是一款基于PHP和MySQL的开源内容管理系统,它提供了丰富的功能和灵活的扩展性,适用于构建多种类型的网站。下面是关于帝国CMS数据库字段的一些说明,这些信息主要集中在购物车数量限制、提交订单权限以及同一IP注册间隔限制等方面。购物车数量限制字段名…

帝国cms数据库在哪

帝国CMS(EmpireCMS,简称ECMS)的数据库文件和配置通常位于以下几个位置:数据库文件位置:帝国CMS的数据库通常是存放在MySQL数据库服务器中的,而不是以文件的形式存储在服务器上。不过,如果你指的是数据库备份文件,那么这些文件通常位于帝国CMS安装目录下的data目录中。例…

帝国cms更换域名后图片地址更换的方法

当帝国CMS更换域名后,图片地址也需要相应的更新,以确保图片能够正常显示。以下是更换域名后更新图片地址的一些方法: 1. 替换数据库中的图片路径 对于帝国CMS来说,图片路径通常存储在数据库中。因此,更换域名后,需要更新数据库中存储的图片路径。 方法:导出数据库:先备…

帝国cms模板怎么制作

制作帝国CMS的模板涉及到了解HTML、CSS、JavaScript以及帝国CMS自身的模板标签和语法。下面是一个简单的指南,帮助你开始制作帝国CMS的模板。 1. 准备工作了解基础:熟悉HTML、CSS和JavaScript的基础知识。 学习帝国CMS模板语法:掌握帝国CMS的模板标签和语法。2. 设计模板布局…

给 DSL 开个脑洞:无状态的状态机

阿里妹导读:什么是 DSL ?DSL 是一种工具,其核心价值在于提供了一种手段,可以更加清晰地就系统某部分的意图进行沟通。本文将通过实现一个状态机引擎来看清 DSL 的本质,介绍状态机的核心模型和 Fluent 接口,并解决状态机的性能问题。最近在一个项目中,因为涉及很多状态的…

帝国cms编辑 帝国cms编辑器不能粘贴复制文字

当帝国CMS的编辑器不能粘贴复制文字时,可能是因为编辑器的某些设置或浏览器的限制导致的。以下是一些可能的解决方案: 1. 检查编辑器设置 确保编辑器的设置允许粘贴和复制。 解决方法:查看编辑器选项:在帝国CMS的后台,检查编辑器的设置,确保允许粘贴和复制操作。 使用粘贴…

FFmpeg开发笔记(五十三)移动端的国产直播录制工具EasyPusher

​EasyPusher是一款国产的RTSP直播录制推流客户端工具,它支持Windows、Linux、Android、iOS等操作系统。EasyPusher采用RTSP推流协议,其中安卓版EasyPusher的Github托管地址为https://github.com/EasyDarwin/EasyPusher-Android。不过EasyPusher有好几年没更新了,尤其安卓版…

帝国cms 您的用户名、密码或安全答案有误,也可能您的帐号已被禁用,请重输

当你忘记了帝国CMS 的后台密码时,可以通过直接修改数据库中的用户信息来重置密码。以下是重置密码的步骤: 步骤1:进入phpMyAdmin 首先,你需要登录到你的服务器,并通过phpMyAdmin或者其他的数据库管理工具访问你的数据库。 步骤2:找到phome_enewsuser数据表 在数据库管理工…

安装帝国cms时输入安装地址,出现404错误

当你在安装帝国CMS时输入安装地址却遇到404错误,这意味着服务器无法找到你所请求的安装脚本页面。这个问题可能是由多种因素引起的,以下是一些常见的解决方法: 1. 检查安装包是否完整 确保你下载的帝国CMS安装包是完整的,并且所有文件都已正确上传到服务器。 解决方法:重新…

帝国cms刷新首页空白怎么办

当帝国CMS刷新首页后出现空白的情况时,这可能是由多种原因造成的。以下是一些常见的解决方法: 1. 检查数据库连接 确保数据库连接正常。 解决方法:检查数据库配置:打开e/config/config.php文件,确认数据库连接信息(如主机名、用户名、密码、数据库名)正确。 测试数据库连…