当前位置: 首页 > news >正文

TCP如何关闭连接(详细版)

关闭连接的⽅式通常有两种,分别是 RST 报⽂关闭和 FIN 报⽂关闭。
如果进程异常退出了,内核就会发送 RST 报⽂来关闭,它可以不⾛四次挥⼿流程,是⼀个暴⼒关闭连接的⽅式。
安全关闭连接的⽅式必须通过四次挥⼿,它由进程调⽤ close shutdown 函数发起 FIN 报⽂( shutdown 参数须传⼊ SHUT_WR 或者 SHUT_RDWR 才会发送 FIN )。
1 close shutdown 有什么区别
调⽤了 close 函数意味着完全断开连接,完全断开不仅指⽆法接收数据,⽽且也不能发送数据。
此时,调⽤了 close 函数的⼀⽅的连接叫做「孤⼉连接」,如果你⽤ netstat -p 命令,会发现连接对应的进程名为空。
使⽤ close 函数关闭连接是不优雅的。于是,就出现了⼀种优雅关闭连接的 shutdown 函数,它可以控制只关闭 ⼀个⽅向的连接
其中第⼆个参数决定断开连接的⽅式,主要有三种:
1 SHUT_RD(0)
关闭连接的「读」这个⽅向 ,如果接收缓冲区有已接收的数据,则将会被丢弃,并且后续再收到新的数据,会对数据进⾏ ACK ,然后悄悄地丢弃。也就是说,对端还是会接收到 ACK ,在这种情况下根本不知道数据已经被丢弃了。
2 SHUT_WR(1)
关闭连接的「写」这个⽅向 ,这就是常被称为「半关闭」的连接。如果发送缓冲区还有未发送的数据,将被⽴即发送出去,并发送⼀个 FIN 报⽂给对端。
3 SHUT_RDWR(2)
相当于 SHUT_RD SHUT_WR 操作各⼀次,关闭套接字的读和写两个⽅向。
2 FIN_WAIT1 状态的优化
如果 FIN_WAIT1 状态连接很多,我们就需要考虑降低 tcp_orphan_retries 的值。当重传次数超过
tcp_orphan_retries 时,连接就会直接关闭掉(即:新增的孤⼉连接将不再⾛四次挥⼿,⽽是直接发送 RST 复位报⽂强制关闭)。
注: tcp_max_orphans 参数,定义了「孤⼉连接」的最⼤数量。
3 FIN_WAIT2 状态的优化
当主动⽅收到 ACK 报⽂后,会处于 FIN_WAIT2 状态,就表示主动⽅的发送通道已经关闭,接下来将等待对⽅发送FIN 报⽂,关闭对⽅的发送通道。
这时,如果连接是⽤ shutdown 函数关闭的,主动⽅连接可以⼀直处于 FIN_WAIT2 状态,因为它可能还可以发送 或接收数据。
但对于 close 函数关闭的孤⼉连接,由于⽆法再发送和接收数据,所以这个状态不可以持续太久,⽽tcp_fin_timeout 控制了这个状态下连接的持续时⻓,默认值是 60 秒(与 TIME_WAIT 状态持续的时间是相同的)。 它意味着对于孤⼉连接(调⽤ close 关闭的连接),如果在 60 秒后还没有收到 FIN 报⽂,连接就会直接关 闭。
4 TIME_WAIT 状态的优化
TIME_WAIT 的状态尤其重要,主要是两个原因
1 )防⽌收到历史数据,从⽽导致数据错乱的问题
TIME_WAIT 等待时间过短,被延迟的数据包抵达后会发⽣什么呢?
TIME_WAIT 设计为 2MSL ,⾜以让两个⽅向上的数据包都被丢弃,使得原来连接的数据包在⽹络中都⾃然消失,再出现的数据包⼀定都是新建⽴连接所产⽣的。
注:
MSL 全称是 Maximum Segment Lifetime ,它定义了⼀个报⽂在⽹络中的最⻓⽣存时间(报⽂每经过⼀次路由器的转发,IP 头部的 TTL 字段就会减 1 ,减到 0 时报⽂ 就被丢弃,这就限制了报⽂的最⻓存活时间)。
2 )为什么是 2 MSL 的时⻓呢?
这其实是相当于⾄少允许报⽂丢失⼀次。⽐如,若 ACK 在⼀个 MSL 内丢失,这样被 动⽅ ᯿ 发的 FIN 会在第 2 个 MSL 内到达, TIME_WAIT 状态的连接可以应对。
Linux 系统中, MSL 的值固定为 30 秒。
等待⾜够的时间以确保最后的 ACK 能让被动关闭⽅接收,从⽽帮助其正确关闭
3 )假设 TIME_WAIT 没有等待或等待的时间过短,断开连接会造成什么?
如上图红⾊框框客户端四次挥⼿的最后⼀个 ACK 报⽂如果在⽹络中被丢失了,此时如果客户端 TIMEWAIT 过短或 没有,则就直接进⼊了 CLOSE 状态了,那么服务端则会⼀直处在 LAST-ACK 状态。
当客户端发起建⽴连接的 SYN 请求报⽂后,服务端会发送 RST 报⽂给客户端,连接建⽴的过程就会被终⽌。
注:
Linux 提供了 tcp_max_tw_buckets 参数,当 TIME_WAIT 的连接数量超过该参数时,新关闭的连接就不再经历TIME_WAIT ⽽直接关闭。查看系统的 TIME_WAIT 的连接数量:

相关文章:

  • 如何进行 AWS 云监控
  • Meta关闭Spark AR平台:未来规划与影响分析
  • 内存分配算法
  • SpringBoot实现前后端传输加密设计
  • Elasticsearch 基本语法使用
  • 排除挖矿木马
  • Node.js 异步编程深度解析:回调函数、Promise 以及 async/await
  • Vue3 使用 富文本编辑器 wangeditor/editor-for-vue 配置详解
  • MySQL之SUBSTRING 和 SUBSTRING_INDEX函数
  • 个人手机发短信和106短信群发平台的本质区别是什么?
  • 【开发实战】QT5 + 深度学习六大应用案例
  • PCL 移动立方体三维重建——RBF算法【2024最新版】
  • 计算机网络-VRRP工作原理
  • 时下改变AI的6大NLP语言模型
  • 【TDesign】如何修改CSS变量
  • 【391天】每日项目总结系列128(2018.03.03)
  • Angular 响应式表单 基础例子
  • CAP 一致性协议及应用解析
  • ERLANG 网工修炼笔记 ---- UDP
  • Java 23种设计模式 之单例模式 7种实现方式
  • Javascript 原型链
  • nodejs实现webservice问题总结
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • Promise初体验
  • Python打包系统简单入门
  • Sequelize 中文文档 v4 - Getting started - 入门
  • SSH 免密登录
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 从PHP迁移至Golang - 基础篇
  • 当SetTimeout遇到了字符串
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 项目管理碎碎念系列之一:干系人管理
  • ionic入门之数据绑定显示-1
  • ​软考-高级-系统架构设计师教程(清华第2版)【第1章-绪论-思维导图】​
  • ​数据链路层——流量控制可靠传输机制 ​
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • #java学习笔记(面向对象)----(未完结)
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (九)信息融合方式简介
  • (十八)SpringBoot之发送QQ邮件
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • (原创) cocos2dx使用Curl连接网络(客户端)
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • .Net6 Api Swagger配置
  • .NetCore 如何动态路由
  • .NET简谈设计模式之(单件模式)
  • .Net组件程序设计之线程、并发管理(一)
  • @Autowired 和 @Resource 区别的补充说明与示例
  • @RequestBody与@ResponseBody的使用
  • [2021 蓝帽杯] One Pointer PHP
  • [AHOI2009]中国象棋 DP,递推,组合数