进程都杀了,为什么 `netstat` 还能看到端口?

在运维和开发过程中,你可能也遇到过类似的"诡异"现象:某个服务占用端口出了问题,你找到它的 PID,执行了 kill -9 <PID> 强制杀掉进程。但当再次用 netstatss 检查时,却发现该端口依然留在列表中:

bash 复制代码
$ netstat -anop | grep 8000
tcp  0  1 [已脱敏IP]:8000  [已脱敏IP]:23331  FIN_WAIT1  -  on (0.15/1/0)
tcp  0  1 [已脱敏IP]:8000  [已脱敏IP]:24535  FIN_WAIT1  -  on (0.18/1/0)

进程明明已经死了(PID 变成了 -),为什么端口连接还在?这个 FIN_WAIT1 到底是什么?在这些 FIN_WAIT1 连接消失之前,其他程序还能使用这个端口吗?本文将为你揭开 TCP 连接生命周期与操作系统内核接管机制的幕后真相。

01 | 关键概念:LISTEN 端口 vs ESTABLISHED 连接

在解答这个问题之前,首先需要厘清操作系统中的两种网络状态:

  1. 监听端口(LISTEN):应用程序通过绑定并监听某个端口,随时准备接收新的连接请求。
  2. 已建立的连接(ESTABLISHED):客户端与服务端完成"三次握手"后建立的通信通道。

当你执行 kill -9 杀掉进程时,应用程序绑定的 LISTEN 监听端口已经被立刻释放了 。这也是为什么在上面的 netstat 输出中,你再也找不到 [已脱敏IP]:8000 LISTEN 这一行。

然而,那些已经建立好的 TCP 连接,其生命周期并不会随着应用程序的死亡而立刻画上句号。
flowchart LR subgraph 进程存活时 A应用程序进程 -->|bind + listen| BLISTEN 监听端口 A -->|accept| CESTABLISHED 已建立连接 end subgraph kill -9 之后 D应用程序进程已死 -.->|立即释放| ELISTEN 监听端口消失 D -.->|内核接管 Socket 句柄| FESTABLISHED 连接转为 FIN_WAIT1 end B --> E C --> F

02 | 什么是 FIN_WAIT1

全称 :Finish Wait 1(终止等待 1 状态),标准写法为 FIN_WAIT_1

TCP 是一种面向连接的、可靠的传输层协议。为了保证数据传输的完整性,不管服务是正常退出还是崩溃被杀,TCP 必须通过"四次挥手"来优雅地关闭连接。

  • 原理 :当一方(这里是你的宿主机内核)决定主动关闭连接时,会向对端发送一个 FIN 数据包,表示"我没有数据要继续发送了,请求断开连接"。
  • 定义 :发出 FIN 包之后、收到对方回应的 ACK 确认包之前,这个 TCP 连接在本地操作系统内部所处的状态就被称为 FIN_WAIT1

stateDiagram-v2 \* --> ESTABLISHED: 三次握手完成 ESTABLISHED --> FIN_WAIT1: 主动发送 FIN 包 FIN_WAIT1 --> FIN_WAIT2: 收到对端 ACK 确认 FIN_WAIT1 --> FIN_WAIT1: 未收到 ACK,指数退避重传 FIN_WAIT2 --> TIME_WAIT: 收到对端 FIN 包 TIME_WAIT --> \*: 等待 2MSL 后关闭

03 | 幕后主使:Linux 内核接管了断开流程

当进程被 kill -9 强制杀死时,发生了以下过程:

  1. 内核接管:应用程序死亡后,操作系统内核会自动接过该进程拥有的所有 TCP Socket 句柄。
  2. 发送 FIN 包 :内核主动向网络对端发送一个带有 FIN 标志位的数据包,告诉对方:"我这边要关闭连接了"。
  3. 卡在 FIN_WAIT1 的原因 :如果对端是公网上的恶意扫描器、发生了网络丢包、或者对端主机宕机,对方就不会正常回应 ACK。Linux 内核会启动指数退避重传机制(如 netstat 中的 on (0.15/1/0)),在重传超时之前,连接会一直处于 FIN_WAIT1 状态。

sequenceDiagram participant App as 应用程序 (PID) participant Kernel as Linux 内核 participant Client as 外部客户端 App->>Kernel: 进程被 kill -9 杀死 Kernel->>Kernel: 接管所有 TCP Socket 句柄 Kernel->>Client: 发送 FIN 包(主动关闭连接) alt 客户端正常响应 Client-->>Kernel: 回应 ACK 确认包 Kernel->>Kernel: 连接进入 FIN_WAIT2,继续完成四次挥手 else 客户端无响应(丢包/宕机/恶意扫描器) Client--xKernel: 无 ACK 回应 Kernel->>Kernel: 指数退避重传 FIN 包<br/>netstat 显示 on (0.15/1/0) Note over Kernel: 连接暂时卡在 FIN_WAIT1<br/>直到重传超时后强制销毁 end

04 | FIN_WAIT1 没消失,其他程序能用这个端口吗?

结论:在开启 SO_REUSEADDR 的情况下,通常可以正常绑定,不会报错!

很多人的误区在于把"连接状态"和"监听端口"混为一谈了,担心启动新程序会报 Address already in use(地址已被占用)的错误。实际上不会,原因如下:

  1. 端口"监听权"已经释放 :报"端口被占用"错误的常见原因是有另一个进程正在 LISTEN 状态下占用该端口;此外,若未开启 SO_REUSEADDR,处于 TIME_WAIT 等状态的残余连接也可能导致绑定失败。杀掉原进程后,LISTEN 句柄已被立即释放,残留的 FIN_WAIT1 只是连接在做收尾清理,并不占据端口的"监听权"。
  2. SO_REUSEADDR 机制保障 :多数现代 Web 框架(如 FastAPI、Uvicorn、Spring Boot、Nginx 等)在创建端口监听时,默认会开启系统级的 SO_REUSEADDR 选项,但具体行为需以所用框架和版本为准。这个选项告诉操作系统:"只要没有其他进程在 LISTEN,即便该端口上还有处于挥手/清理状态(如 FIN_WAIT1TIME_WAIT)的残余连接,也允许新程序直接绑定并监听该端口。"

flowchart TD A新程序尝试绑定端口 8000 --> B{是否有进程在 LISTEN?} B -->|是| C报错 Address already in use B -->|否| D{端口上是否存在残余连接?<br/>FIN_WAIT1 / TIME_WAIT} D -->|是, 但已开启 SO_REUSEADDR| E允许绑定,新程序正常启动 D -->|否| F允许绑定,新程序正常启动 C --> G需要先处理占用端口的进程 E --> H✅ 新服务正常运行 F --> H

05 | 总结

疑问 / 现象 幕后真相
为什么 PID 变成了 - 进程已死,连接当前由 Linux 内核接管维护。
FIN_WAIT1 是什么? Finish Wait 1(标准写法 FIN_WAIT_1),内核已发出断开请求(FIN),正在等待对端回应 ACK 的中间状态。
会阻塞新程序启动吗? 通常不会。 LISTEN 状态已释放,在开启 SO_REUSEADDR 的情况下,新程序可以立刻绑定该端口。
需要手动处理吗? 通常不需要。内核重传超时后会自动强制销毁,一般不会永久占用资源。

flowchart LR subgraph 现象 Akill -9 杀掉进程 --> Bnetstat 仍显示端口连接 B --> CPID 显示为 - B --> D状态为 FIN_WAIT1 end subgraph 原因 ELISTEN 监听端口已立即释放 --> F新程序可正常绑定端口 G内核接管已建立的 TCP 连接 --> H主动发送 FIN 包等待 ACK H --> I对端无响应时卡在 FIN_WAIT1 end subgraph 结果 J不会报 Address already in use K内核重传超时后自动清理 L无需手动干预 end A --> E A --> G B --> I F --> J I --> K K --> L

下次再遇到杀掉进程后 netstat 里残留 FIN_WAIT1 连接的情况,不用惊慌,直接启动你的新服务即可,这正是 Linux 内核网络协议栈在默默履行其可靠传输职责的表现。

关注我,和AI一起成长~

相关推荐
一条泥憨鱼1 小时前
【从0开始学习计算机网络】| 邮件协议入门:SMTP、POP3、IMAP
linux·运维·计算机网络·github
Johny_Zhao12 小时前
网络安全等级保护测评实施方案
linux·网络·人工智能·网络安全·信息安全·云计算·等保测评·系统运维·itsm
落羽的落羽13 小时前
【AI】快速理解AI应用的相关名词概念
linux·c++·人工智能·python·计算机网络·算法
刚入门的大一新生13 小时前
Linux-进程控制
linux·运维·服务器·c++
上火的金鱼妹13 小时前
K8S基础组件作用和关系整理
linux·运维·服务器·kubernetes
Vcaker13 小时前
Linux学习25-harbor私有仓库部署
linux·运维·学习
刃神太酷啦13 小时前
Redis 进阶核心:持久化 (RDB/AOF)、事务与主从复制全解析----《Hello Redis!》(5)
linux·c语言·数据库·c++·redis·缓存·bootstrap
编程的一拳超人13 小时前
DeepSeek Harness Linux/macOS/Windows 本地下载、启动与模型配置指南
linux·windows·macos·deepseek
时凌云.14 小时前
【2026最新】JDK 下载安装与环境配置全教程(Windows/Mac/Linux 三平台,零基础友好)
java·linux·macos