FrankenPHP启动失败时终端最后一行即关键线索,如“listen tcp :8000: bind: address already in use”表明端口8000被占用;macOS下用lsof -P -n -i :8000精准定位PID和COMMAND,Unix socket残留需手动删除/tmp/frankenphp.sock并清理顽固php进程。

启动失败时终端最后一行就是关键线索
FrankenPHP 启动失败,根本不用翻日志文件——它不写磁盘日志,所有错误都直接输出到终端 stderr。只要看到 bind: address already in use 这类报错,后面紧跟着的地址就是冲突端口,比如 listen tcp :8000: bind: address already in use 说明 :8000 被占了。
常见变体还有:
-
listen tcp :80: bind: permission denied→ 端口 80 被系统服务(如 HTTP.sys)或 root 权限进程占用 -
listen tcp 127.0.0.1:9000: bind: address already in use→ 明确到 IP+端口,可能是旧frankenphp、php-fpm或messenger:consume残留 -
failed to listen on unix:///tmp/frankenphp.sock: bind: address already in use→ Unix socket 文件未清理,不是端口问题,但表现一样
macOS 下用 lsof 精准定位谁在占端口
lsof -P -n -i :8000 是 macOS 上最准的查法,不走 DNS 解析,输出干净。重点看两列:
-
PID:进程编号,后续 kill 用得上 -
COMMAND:进程名,比如frankenphp(旧实例)、php(Symfony worker)、nginx、node,甚至kernel_task(AirPlay 接收等系统服务)
如果 lsof -i :8000 没输出但启动仍失败,换这句强制过滤 TCP LISTEN 状态:
立即学习“PHP免费学习笔记(深入)”;
sudo lsof -iTCP -sTCP:LISTEN | grep :8000
这是为了捕获那些用了 SO_REUSEPORT 或状态异常的监听者,普通 lsof -i 可能漏掉。
Windows 下必须用管理员权限查 netstat
普通 CMD 查不到系统级端口占用,必须以管理员身份运行:
netstat -ano | findstr :80
输出末尾数字是 PID,再用 tasklist | findstr "1234"(把 1234 换成实际 PID)确认进程名。特别注意:
-
PID = 4几乎肯定是System或HTTP.sys,不能taskkill /f /pid 4,否则蓝屏或断网 -
PID对应Skype.exe、sqlservr.exe、httpd.exe就可以安全终止 - 若想绕开冲突,直接改启动命令:
frankenphp serve --addr :8080
别忽略 Unix socket 和 Symfony 残留进程
FrankenPHP 默认用 /tmp/frankenphp.sock 通信,异常退出后这个文件可能残留,导致新实例启动失败,报错里会带 unix:// 路径。此时:
- 先
ls -l /tmp/frankenphp.sock看是否存在 - 存在就
rm -f /tmp/frankenphp.sock - 再检查是否还有
php bin/console messenger:consume这类顽固后台进程——它们常驻内存、不响应 SIGTERM,得用pgrep -f "messenger:consume" | xargs kill -9强杀
真正容易被忽略的是:端口没被占,socket 文件删了,但 php 进程还在后台跑着并 hold 住端口,只靠 pkill php 会误杀新 FrankenPHP 主进程。必须用 ps auxf | grep php 看完整命令行,精准匹配关键词再 kill。



















