发送ACK和RST的场景
在有以下几种情景,TCP会把ack包发出去:
- 收到1个包,启动200ms定时器,等到200ms的定时器到点了(第二个包没来),于是对这个包的确认ack被发送。这叫做“延迟发送”;
- 收到1个包,启动200ms定时器,200ms定时器还没到,第二个数据包又来了(两个数据包一个ack);
- 收到1个包,启动200ms定时器,还没超时,正好要给对方发点内容。于是对这个包的确认ack就跟着捎过去。这叫做“捎带发送”;
- 每当TCP接收到一个超出期望序号的失序数据时,它总是发送一个确认序号为其期望序号的ACK;
- 窗口更新或者也叫做打开窗口(接收端窗口达到最大的时候,接收缓存中的数据全部推向进程导致接收缓存为空),通知发送端可以继续发送;
- 正常情况下对对方保活探针的响应,详见TCP keepalive
以下情况会发送RST包:
- connect一个不存在的端口;
- 向一个已经关掉的连接send数据;
- 向一个已经崩溃的对端发送数据(连接之前已经被建立);
- close(sockfd)时,直接丢弃接收缓冲区未读取的数据,并给对方发一个RST。这个是由SO_LINGER选项来控制的;
- a重启,收到b的保活探针,a发rst,通知b。
TCP socket在任何状态下,只要收到RST包,即可进入CLOSED初始状态。值得注意的是RST报文段不会导致另一端产生任何响应,另一端根本不进行确认。收到RST的一方将终止该连接。
原文链接:
https://www.cnblogs.com/549294286/p/5100076.html.
TIME_WAIT状态
- tcp断开连接需要经过四次挥手的过程,这时候最后的ACK由主动关闭端发出,此时主动关闭端状态为TIME_WAIT
- 为什么需要TIME_WAIT状态:
- 主动关闭的Socket端会进入TIME_WAIT状态,并且持续2MSL时间长度,MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间将在网络中消失。
- 已经主动关闭连接了为什么还需要保持资源一段时间呢:
防止上一次连接中的包,迷路后重新出现,影响新连接
(经过2MSL,上一次连接中所有的重复包都会消失)可靠的关闭TCP连接。
动关闭方发送的最后一个 ack(fin) 有可能丢失,这时被动方会重新发fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。另外这么设计TIME_WAIT 会定时的回收资源,并不会占用很大资源的,除非短时间内接受大量请求或者受到攻击。
图示:
产生大量TIME_WAIT原因
- 一些爬虫服务器或者WEB服务器(如果网管在安装的时候没有做内核参数优化的话)上经常会遇到这个问题
- 在高并发短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于TIME_WAIT状态。如果客户端的
并发量持续很高
,此时部分客户端就会显示连接不上。
解决办法
解决思路
优化内核参数,让服务器能够快速回收和重用那些TIME_WAIT的资源具体实现
编辑内核文件/etc/sysctl.conf,加入以下内容:
net.ipv4.tcp_syncookies = 1 %表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1 %表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 %表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout %修改系默认的 TIMEOUT 时间
执行 /sbin/sysctl -p 让参数生效:
/etc/sysctl.conf是一个允许改变正在运行中的Linux系统的接口,它包含一些TCP/IP堆栈和虚拟内存系统的高级选项,修改内核参数永久生效。