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 的连接数量:

相关推荐
阿巴~阿巴~4 小时前
JsonCpp:C++ JSON处理利器
linux·网络·c++·json·tcp·序列化和反序列化
ao_lang4 小时前
数据链路层
linux·服务器·网络
执笔论英雄5 小时前
【RL】python协程
java·网络·人工智能·python·设计模式
不过普通话一乙不改名6 小时前
Linux 网络发包的极致之路:从普通模式到 AF_XDP ZeroCopy
linux·运维·网络
Macbethad6 小时前
Profinet主站程序技术方案
网络协议·信息与通信
4***17547 小时前
linux 网卡配置
linux·网络·php
XiaoCCCcCCccCcccC8 小时前
多路复用 poll -- poll 的介绍,poll 的优缺点,poll 版本的 TCP 回显服务器
服务器·网络·c++
多看书少吃饭8 小时前
小程序支持HTTP POST 流式接口吗?
网络协议·http·小程序
陈奕昆8 小时前
n8n实战营Day2:复杂逻辑控制·HTTP请求+条件分支节点实操
网络·人工智能·python·网络协议·n8n
h***04778 小时前
IEEE 1588:电信网络的精确时间协议 (PTP)
网络