服务器主动发FIN包通常发生在四类时刻:应用代码调用close()/shutdown()、服务端连接空闲超时回收、服务端进程退出或崩溃、反向代理或负载均衡主动断开,排查时先抓包看Flags [F.]最先出现在服务器端口还是客户端端口。
服务器主动断开tcp连接的原因
TCP连接的关闭不是瞬间完成的,服务器主动发FIN包,意味着服务器作为关闭发起方,先告诉客户端“我这边的数据已经发完,可以关闭连接了”,底层对应TCP四次挥手,FIN是第一次挥手,真正让服务器发出这个FIN包的原因,基本集中在下面几类场景。
应用层主动调用关闭函数
大多数后端服务在完成一次响应后,会根据协议决定是否关闭连接,代码里执行一次关闭操作,内核就会构造并发送FIN包。
- Java中调用
socket.close()或serverSocket.close()会触发FIN。 - C语言中调用
close(fd)或shutdown(fd, SHUT_WR)会发送FIN,后者只关闭写端。 - Python中调用
socket.close()、Go中调用conn.Close()同理。 - HTTP/1.1里如果服务端返回
Connection: close响应头,服务器在发送完响应体后主动关闭TCP连接,发送FIN包,短连接HTTP接口大多走这条路。 - 部分RPC框架在服务端处理完请求后,如果客户端没有复用连接,服务端会主动发FIN回收描述符。
判断方法很简单:在服务器上执行ss -tan state fin-wait-1,如果看到连接进入FIN_WAIT_1状态,说明本机刚刚发出FIN包。
服务端超时参数触发FIN
线上最容易出现“服务器主动发FIN包”的场景,不是应用代码刻意关闭,而是服务端配置的空闲超时到期,服务端进程在实现长连接时,会设置一个空闲阈值,超过阈值没有数据交互,就主动断开。
- Nginx配置
keepalive_timeout 65;,到期后Nginx主动向客户端发FIN。 - Tomcat在HTTP连接器里配置
connectionTimeout="20000",连接空闲超过该值会被服务端关闭并发FIN。 - Redis配置
timeout 300,客户端空闲300秒后Redis服务端主动发FIN断开。 - MySQL的
wait_timeout=28800,连接空闲8小时后MySQL服务端发FIN关闭连接。 - HAProxy、Envoy等代理也有
timeout client、timeout server参数,到达阈值后由代理代替后端发FIN。
这些超时参数造成的FIN包,通常是服务端先发FIN,进入FIN_WAIT_1,接着完成四次挥手,客户端如果还在复用连接,就会出现客户端报“connection reset”或“broken pipe”的奇怪现象,实际抓包往往看到的是FIN不是RST。

进程退出、崩溃和OOM杀手触发
服务端进程正常退出或异常崩溃时,操作系统内核会代为关闭该进程持有的所有socket,如果socket上还有未处理完的数据,内核会按照正常关闭流程发FIN包。
systemctl restart nginx、kill掉一个Java进程、或者容器被Kubernetes驱逐,都会触发内核发FIN。- 如果进程被OOM Killer杀死,内核同样会清理socket,多数情况下发的是FIN,但如果socket设置了
SO_LINGER且linger=0,内核可能直接发RST。 - 部署新版本时滚动重启,旧进程退出时会对所有存量连接发FIN,客户端表现为连接被正常关闭。
查这类原因可以看两个地方:一是journalctl -u 服务名 --since "10 min ago",二是dmesg | grep -i oom,如果进程重启时间与抓包时间接近,基本可以判定是退出触发FIN。
反向代理、负载均衡和健康检查
四层或七层负载均衡在健康检查、连接回收时也会主动发FIN,云负载均衡转发客户端连接给后端,如果后端存活探测结束或者连接数超出阈值,负载均衡可能主动向后端或客户端发FIN。
- 四层LB在做健康检查时,可能先完成TCP握手,再发FIN关闭探测连接。
- 七层Nginx作为反向代理,与上游服务器之间的keepalive连接超时后,Nginx会主动向上游发FIN。
- 某些云安全网关检测到空闲连接,可能先发FIN释放会话表项。
服务器主动发FIN包与RST包的区别场景
业内专家指出,抓包时如果看到Flags [R]而服务器端口没有监听,基本是内核代替响应RST,FIN和RST虽然都表示连接结束,但语义完全不同。
| 对比维度 | FIN包 | RST包 |
|---|---|---|
| 关闭性质 | 正常四次挥手,允许对方继续发送剩余数据 | 异常终止,连接立即不可用 |
| 触发条件 | close()、shutdown()、超时到期、进程退出 | 访问未监听端口、连接半开、防火墙reject、SO_LINGER=0 |
| TCP状态 | FIN_WAIT_1或FIN_WAIT_2,最终进入TIME_WAIT | 直接CLOSED,或SYN_SENT收到RST |
| 抓包特征 | Flags [F.],可能包含ACK | Flags [R]或[R.] |
| 对方感受 | 收到FIN后仍可发送数据完成半关闭 | 未读数据直接丢弃,连接不可恢复 |
| 典型场景 | Nginx keepalive_timeout到期、应用正常退出 | 客户端连错端口、服务端进程崩溃后内核发RST |
服务器主动发FIN包一般代表服务端是“有意关闭”,而RST多数代表“拒绝”或“异常中断”,排障时先区分这两种包,能少走很多弯路。
云服务器主动断开连接怎么排查
云服务器主动发FIN时,排查链路比物理机稍长,因为中间可能经过安全组、NAT网关、负载均衡,FIN包方向容易被误判,行业共识认为,排查FIN应先排除配置超时,再查进程退出。
第一步:抓包确认FIN发起方
在Linux服务器上执行:
tcpdump -i eth0 'tcp[tcpflags] & (tcp-fin) != 0' -nn
如果看到源IP是服务器自己,目的端口是客户端高端口,说明服务器主动发FIN,用Wireshark打开抓包文件,过滤条件写成:
tcp.flags.fin==1 && tcp.flags.ack==1
重点看FIN包的序列号,正常关闭时,FIN的序列号等于之前发送数据段的结束序列号,表示数据发完后才关闭,如果序列号异常跳变,可能是连接被中间设备接管。
第二步:核对服务超时参数
多数云服务器主动发FIN,都是服务端超时参数配置得太短,下面几个常见参数要逐个检查:
| 服务 | 参数 | 常见值 | 主动断开场景 |
|---|---|---|---|
| Nginx | keepalive_timeout | 65s/75s | 客户端空闲超时后无新请求 |
| Tomcat | connectionTimeout | 20000ms左右 | HTTP连接器空闲超时 |
| Redis | timeout | 300s或0 | 0表示禁用,300表示空闲300秒断开 |
| MySQL | wait_timeout | 28800s | 连接空闲8小时后断开 |
| SSH | ClientAliveInterval | 0表示不断开 | 非0值时服务端探测失败后断开 |
修改参数后执行nginx -s reload或重启对应服务,再用ss -tan观察FIN_WAIT_1和TIME_WAIT数量变化。
第三步:检查进程退出与OOM
如果服务端配置正常,但依然频繁主动发FIN,就要查进程是不是在反复重启。
查看命令:
journalctl -u nginx --since "10 min ago"
dmesg | grep -i kill
grep -i 'out of memory' /var/log/messages
如果进程退出时间与FIN抓包时间重合,说明是退出触发,容器环境里执行kubectl describe pod看Last State,如果显示OOMKilled,跑在容器内的服务会被内核强制清socket发FIN或RST。
北京云服务器主动发FIN包怎么办

北京地域云服务器部署密度高,跨地域访问经过的链路层设备更多,如果用户在北京地域购买云服务器后,连接每隔几分钟就被断开一次,先不要只看服务器配置,可以在服务器本地抓包,同时在北京地域控制台查看实例监控里的“连接数”曲线。
如果服务器本地抓包显示FIN确实由服务器发出,按超时参数和进程退出排查,如果服务器本地没有抓到FIN,但客户端一直报“远程主机强制关闭连接”,可能是北京地域的公网NAT或负载均衡空闲超时更短,先于服务器回收会话,此时可以调整客户端的keepalive间隔,让链路保持活跃,避免中间设备提前发FIN。
按量计费云服务器连接频繁断开的成本提醒
按量计费云服务器如果因应用频繁短连接,每次请求都重新完成TCP握手和四次挥手,会放大网络资源消耗,虽然FIN包本身不单独计费,但高频连接会带来三方面开销:公网流量增加、CPU中断处理上升、连接数巨增导致实例性能抖动。
如果业务本身可以复用连接,建议启用HTTP keepalive或数据库连接池,减少按量计费云服务器连接频繁断开带来的隐性成本,合理设置超时时间,比单纯调大超时更划算。
服务器什么时候发送fin包?常见问题解答
服务器什么时候发送fin包?
服务器在应用层调用close()/shutdown()、服务端连接空闲超时到期、服务端进程退出或被OOM Killer杀死、反向代理或负载均衡主动回收连接时,会发送FIN包,抓包中源IP为服务器且Flags为[F.],就可以判断是服务器主动发起关闭。
服务器主动发FIN包和客户端断开有什么不同?
区别主要体现在FIN发起方和TIME_WAIT位置,服务器主动断开时,服务器先发FIN,随后进入FIN_WAIT_1、FIN_WAIT_2,最后停在TIME_WAIT,客户端主动断开时,客户端先发FIN,TIME_WAIT大量出现在客户端,服务器上执行ss -tan | grep TIME_WAIT,如果TIME_WAIT集中在服务器本机,说明服务器主动关闭连接更多。
服务器主动发FIN包一定是应用层执行close吗?
不一定,应用层close只是其中一种,服务端超时参数到期、进程退出后内核代发、负载均衡回收空闲连接,都会让服务器发出FIN包,反过来,如果抓包看到的是RST,那通常不是正常close路径,而是端口未监听、连接半开或者安全策略拒绝。
判断服务器何时主动发FIN,不要只看连接中断的表象,先抓包确认FIN方向,再对照超时参数和进程重启时间,多数线上问题都能在超时参数或应用关闭逻辑里找到答案。
图片来源于AI模型,如侵权请联系管理员。作者:酷小编,如若转载,请注明出处:https://www.kufanyun.com/ask/808346.html

