端口被占用导致workerman启动失败,需依次执行四步:1.用lsof或netstat查占用进程;2.用pgrep或killall清理残留子进程;3.同步更新gatewayworker的register地址;4.升级workerman或指定pidfile路径避免假重启。

Workerman启动时提示“Address already in use”,说明你要监听的端口(比如8282、7272或1236)正被另一个进程独占,系统拒绝重复绑定——这不是代码写错了,而是端口资源冲突问题,必须先清空占用者才能继续。
第一步:确认哪个进程在抢你的端口
Linux/macOS下直接运行:lsof -i :8282(把8282换成你报错里写的实际端口号)。这命令会立刻列出进程名、PID和用户,不用猜、不绕路。
如果提示 command not found,说明系统没装lsof:Alpine镜像用apk add lsof,Ubuntu/Debian用apt install lsof。
【注意】别只查0.0.0.0:8282,IPv6地址:::8282也可能在偷偷占着端口,lsof -i :8282能同时覆盖两者。
Windows用户请用:netstat -ano | findstr :8282,再用tasklist | findstr 12345(12345替换成上一步看到的PID)查进程名。
第二步:干掉残留的Workerman子进程
Workerman是多进程模型,主进程fork出多个worker。一旦上次异常退出(比如直接关终端、kill -9主进程、服务器断电),子进程可能还在后台跑着,继续霸占端口。
先扫一眼有没有漏网之鱼:ps aux | grep "start.php" 或 ps aux | grep YourAppPath。
别只kill主进程PID——要一锅端:kill -9 $(pgrep -f "YourAppPath/start.php")。这条命令会精准匹配所有含start.php路径的php进程并全部杀掉。
开发环境可加临时清理逻辑(生产环境禁用):在start.php最开头插入一行:exec("killall -u $(whoami) php 2>/dev/null");。
第三步:检查register地址是否同步更新
GatewayWorker架构里有两层监听:业务worker(比如new Worker("websocket://0.0.0.0:7272"))和register worker(默认127.0.0.1:1236)。你改了业务端口,但register还卡在旧地址,或者客户端连的仍是旧register地址,就会导致启动失败或连接不上。
方法一:启动时显式指定register新地址:php start.php start -d --register-addr=127.0.0.1:1237。
方法二:检查start_register.php中register worker的监听配置,确保IP和端口与业务worker调用时传入的一致。
方法三:客户端连接代码里,register地址必须同步改成新端口,否则即使服务端启动成功,客户端也注册不进去。
第四步:验证pidFile是否失效
Workerman 3.2.2之前版本默认把pid文件存在/tmp/目录,而很多Linux系统会定时清空/tmp,导致restart时找不到主进程PID,退化成“假重启”——旧worker还在跑,新worker起不来,日志只报一句Address already in use。
升级Workerman到3.2.2或更高版本,pidFile默认改存到项目目录下,不再依赖/tmp。
或者手动指定安全位置:Worker::$pidFile = __DIR__ . '/workerman.pid';,放在start.php开头即可。
执行php start.php kill(Workerman 3.2.2+支持)比手动kill更可靠,它会读pidFile并精准终止主进程及其全部子进程。











