linux/macos下查端口占用首选ss命令:ss -tulnp | grep ':9502'可精准显示pid和进程名;若无输出但启动失败,可能是time_wait状态或服务未真正运行;慎用kill -9,优先优雅终止swoole主进程。

端口被占用了,php ws_server.php 启动直接报 failed to listen server port[0.0.0.0:9502], Error: Address already in use,别急着重装或改端口,先查清是谁在用、为什么没释放。
netstat 或 ss 查端口监听状态
Linux/macOS 下优先用 ss,比 netstat 更快更准,且无需额外安装:
-
ss -tulnp | grep ':9502'—— 替换9502为你实际想用的端口,输出里会带pid和进程名(如php、java) - 如果返回空但服务仍启不来,可能是端口处于
TIME_WAIT状态,不是真被占,而是内核还没回收;这时可等几十秒再试,或临时加setsockopt(SO_REUSEADDR)(Swoole 默认已启用) -
netstat -anp | grep ':9502'也能用,但部分系统需 root 权限才显示 PID,非 root 用户可能只看到-
lsof 找不到命令?别装 lsof,用 pidof 或 pgrep 替代
lsof -i :9502 报 command not found 很常见,尤其在最小化安装的 CentOS/Alpine 上。没必要为查个端口专门装 lsof:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
-
pidof php—— 如果你确定是 PHP 进程占的,直接列出所有 PHP 进程 PID -
pgrep -f 'ws_server\.php'—— 按脚本名模糊匹配,更精准(注意转义点号) -
ps aux | grep 9502—— 配合ps看完整命令行,确认是不是残留的 Swoole 主进程或 worker 进程
kill -9 不一定安全,先试优雅终止
Swoole 进程有主进程 + worker 子进程结构,直接 kill -9 可能留下僵尸 worker 或未清理的共享内存:
- 先尝试
kill <pid></pid>(不带-9),给主进程机会执行onShutdown回调、关闭连接、释放资源 - 如果
kill后端口仍被占,再用kill -9 <pid></pid>;但注意:Swoole 6.x 起默认启用enable_reuse_port => true,有时ss显示端口还在监听,其实是内核级复用,不影响新进程绑定 - 若 kill 后发现
ps aux | grep swoole还有一堆子进程,说明主进程没管好子进程退出,检查代码里是否漏了$server->shutdown()或配置了daemonize => true却没配pid_file,导致无法追踪主进程
Nginx 反向代理后端口“假占用”
你改了 Nginx 配置指向 127.0.0.1:9502,但 Swoole 服务根本没跑,Nginx 却卡在连接超时,这时候浏览器连 wss://your.com/ws 会报 502,而 ss -tulnp 看不到 9502 —— 它压根没被监听。这不是端口占用,是服务没启。
- 务必先本地直连验证:
curl -i http://127.0.0.1:9502或用 WebSocket 客户端工具(如 wscat)连ws://127.0.0.1:9502 - 如果直连失败,再查端口;如果直连成功但 Nginx 代理失败,问题在 Nginx 配置里的
proxy_http_version 1.1、Upgrade和Connection头是否写全 - 别忽略防火墙:云服务器安全组、
ufw、firewalld都可能拦掉 9502,但它们不会让ss显示端口被占,只会让连接超时
真正难处理的不是“端口被谁占了”,而是“为什么杀完又回来”——比如守护进程自动拉起、Supervisor 配置了 autostart=true 却没关、Docker 容器重启策略设为 always。查 PID 之前,先想清楚:这进程,是你手动起的,还是某个自动化机制在管?










