启动报错,netstat 却查不到进程
本地起一个 Spring Boot 项目,控制台突然报错:
Web server failed to start. Port 8123 was already in use。
照习惯打开 PowerShell 跑 netstat -ano | findstr :8123,想看看是哪个进程占着。
结果空空如也,没有任何输出。
这至少说明 netstat 没看到 8123 当前存在对应的监听项。
可 Spring Boot 偏偏还是启动失败了。
netstat 查不到,可能是系统排除了这个端口
开过 WSL2、Docker Desktop,或者其他依赖 Hyper-V、WinNAT 的虚拟化环境后,Windows 上可能会出现一些排除的端口范围。
启动项目时,如果恰好撞上这些范围,就可能出现端口无法绑定的情况。
Windows 会维护一组 Excluded Port Ranges。
这些端口不会像普通监听端口那样出现在 netstat 的监听列表里,但应用尝试绑定这些端口时,仍然可能失败。
Windows 把这段端口划成了禁区,并没有程序在监听它。
因此 netstat 里看不到任何进程,也就没法像普通端口占用那样顺着 PID 去定位。
当 Java、Node.js 或者 Python 等用户态程序尝试绑定这些端口时,Windows 可能直接拒绝这次绑定。
到了应用层,Spring Boot 可能仍然把这类绑定失败归纳成"端口已被占用"。
用 netsh 看系统到底留了哪些端口
普通进程正在监听端口时,可以用 netstat 查看对应的监听项和 PID;
如果查不到监听项,但应用仍然无法绑定,就可以进一步检查系统排除的端口范围。
要用另一套命令,以管理员身份打开 PowerShell,执行:
netsh interface ipv4 show excludedportrange protocol=tcp
如果应用使用 IPv6,还可以顺带检查对应的 IPv6 排除范围:
netsh interface ipv6 show excludedportrange protocol=tcp
输出长这样:
Protocol tcp Port Exclusion Ranges
Start Port End Port
---------- --------
1103 1202
1403 1502
5251 5350
8082 8181
50000 50059 *
每一行表示一段被排除的 TCP 端口范围。
假设你在自己的机器上看到:
8082 8181
而你要用的端口是 8123,它正好落在这个区间里,这时 8123 无法绑定的原因就找到了。
找到排除范围后,先换到范围之外
很多教程一上来就让你换个端口,比如改成 8124。
这么做本身没有错,但如果不先确认排除范围,下一次换的端口照样可能落在另一个排除区间里。
如果已经确认 8123 落在系统排除范围内,就换一个不在任何排除范围内的端口。
比如当前排除范围是:
8082 8181
那么 8123 就不要再用了,可以改成 8200。
改完后再次执行 netsh interface ipv4 show excludedportrange protocol=tcp,确认 8200 不落在任何排除范围内,再启动 Spring Boot。
注意不要把"动态端口范围"和"排除的端口范围"混为一谈。
后者是 Windows 标记为排除的区间,应用通常不能正常绑定;
修改动态端口范围,并不会自动删除已经存在的 excluded port range。
少数情况下你确实想主动释放某个排除范围,微软提供了 delete excludedportrange 命令,但它要求起始端口和数量精确匹配当初创建的范围,如果这个排除范围是其他系统组件创建的,手动删除后也可能再次出现,所以本篇不把它当成标准做法。
回到 IDE 重新启动 Spring Boot,看到 Started Application in x seconds,问题就解决了。
两种排查方式,适用场景不一样
端口被占用,先别急着怀疑自己的代码。
netstat 查不到监听进程,但端口仍然无法绑定时,可以进一步检查 Excluded Port Ranges。
| 排查方式 | 查什么 | 适用场景 |
|---|---|---|
netstat -ano | 查看 TCP/UDP 连接、监听项和 PID | 怀疑有普通进程正在占用端口 |
netsh interface ipv4 show excludedportrange protocol=tcp | 查看系统排除的 TCP 端口范围 | 查不到监听进程,但端口仍无法绑定 |