端口80被占用怎么解决

Windows 上跑 `netstat -ano | findstr :80`,端口看到一行 `TCP 0.0.0.0:80 0.0.0.0:0 LISTENING 4`,被占PID 是用解 4。4 是端口 System 进程,不是被占某个普通程序。这种情况十有八九是用解 IIS 或者 SQL Server Reporting Services 在背后占着 80。

很多人第一反应是端口去任务管理器找 PID 4 然后结束它。找不到的被占。System 进程不给你结束,用解也不需要结束。端口真正要处理的被占是它下面挂着的那个服务。

先搞清楚谁在占

PID 4 对应的用解常见嫌疑犯有几个:IIS 的 W3SVC 服务、SQL Server Reporting Services、端口Web Deployment Agent Service、被占BranchCache。用解还有一个容易被忽略的——WinHTTP Web Proxy Auto-Discovery Service,不过这货一般占的是 127.0.0.1:80 而不是 0.0.0.0:80。

怎么确认?打开 services.msc,挨个看这几个服务的状态。或者更直接一点,管理员权限开 PowerShell:

Get-Process -Id 4 | Select-Object -ExpandProperty Modules | Where-Object { $_.FileName -like "*http*"}

不过说实话,这个方法输出不太友好。更省事的做法是直接执行 `netsh http show servicestate`,它会列出所有注册到 HTTP.sys 的 URL 和对应的进程。80 端口被谁注册了,一目了然。

我自己的经验是,十次里面有六次是 IIS。Windows 10/11 默认不装 IIS,但只要你开过“Internet Information Services”这个功能,或者装过某些会捆绑 IIS 的软件(比如一些老版本的 Visual Studio 工作负载),它就会自动启动。

处理办法

确认了是 IIS 的话,最干净的做法不是卸载,而是停掉它。管理员 CMD 里跑 `iisreset /stop`,80 端口立刻释放。如果你压根不用 IIS,那就把 W3SVC 服务设成禁用,省得下次开机又来抢。

SQL Server Reporting Services 也类似。去 services.msc 找到 SQL Server Reporting Services,停掉,改成手动启动。除非你确实在用 SSRS 出报表,否则没必要让它常驻。

Web Deployment Agent Service 这个东西比较隐蔽,装了 Web Deploy 之后它就会在 80 上监听。停掉就行,不影响正常开发。

还有一种情况:PID 不是 4,而是某个具体的程序。比如你之前跑了个 nginx 或者 Apache 没关干净,或者某个 Electron 应用内置了 HTTP 服务。这种直接 `taskkill /PID xxx /F` 就完了。

但有时候你会发现,`taskkill` 报“拒绝访问”。这说明那个进程有更高的权限。用管理员身份开 CMD 再试一次,基本都能解决。

改端口还是杀进程

有人建议把 IIS 的绑定端口从 80 改成 8080。可以,但没必要。IIS 你如果不用,停掉是最省事的。你如果真在用 IIS 托管站点,那 80 本来就该归它,你要做的是把你自己的开发服务器换个端口。

Node.js 的话,`app.listen(3000)` 改个数字就行。Python 的 `http.server` 默认 8000,一般不会撞。真正容易撞 80 的是那些默认配置里写死 80 的轻量级服务器,比如某些 Go 写的静态文件服务,或者 Caddy 的默认配置。

我自己的习惯是:开发环境永远不用 80。用 3000、8080、9090 这些,省得跟系统服务打架。部署到服务器上再走 80 或者 443,那是另一回事。

一个小技巧

如果你经常需要查端口占用,可以在 PowerShell 的 profile 里加一个函数:

function port($p) {  netstat -ano | findstr ":$p " }

以后直接 `port 80` 就行。比每次敲完整命令省事。Windows 的 netstat 输出确实丑,但配合 findstr 够用了。实在嫌麻烦,装个 TCPView,图形界面,谁占了一眼就能看到。

端口冲突这种事,本质上是信息不对称。你知道谁在占,就知道怎么处理。不知道的时候才会觉得烦。