确认workerman进程是否真正在监听端口,需用ss -tuln | grep :端口验证内核监听状态;若仅显示127.0.0.1则外部不可访问,应绑定0.0.0.0;ps aux需见worker进程,无则检查onWorkerStart异常;客户端须telnet服务器真实IP,同时排查安全组、防火墙、docker绑定及TIME_WAIT问题。

确认 Workerman 进程是否真正在监听端口
很多人看到 php start.php start 输出 “Start success”,就以为服务起来了,其实可能只是主进程启动了,Worker 子进程因配置错误、代码异常或权限问题根本没起来。最直接的验证方式是查系统级监听状态,而不是只看 Workerman 日志。
- linux/macos 上用
ss -tuln | grep :2345(把2345换成你实际监听的端口),有输出才说明内核确实在监听;没有输出,90% 是 Workerman 没跑起来或监听失败 - 如果看到
127.0.0.1:2345但看不到*:2345,说明 Workerman 绑定了localhost,外部客户端连不上——得检查$worker->listen('tcp://0.0.0.0:2345')或'tcp://*:2345',不能写成'tcp://127.0.0.1:2345' - Workerman 启动后,
ps aux | grep WorkerMan应该能看到至少一个WorkerMan: worker process进程;只有master process而没有 worker,基本是onWorkerStart抛了未捕获异常,去workerman.log最末尾找Fatal Error或Exception
本地 telnet 能通 ≠ 客户端能连,重点看目标 IP 和网络路径
在服务器上 telnet 127.0.0.1 2345 成功,只说明本机 loopback 通;客户端连不上,大概率卡在中间某一层:本机防火墙、云厂商安全组、NAT 网关、甚至客户端所在局域网出口策略。
- 从客户端机器直接执行
telnet your-server-ip 2345—— 这步必须做,不能只信服务器上的测试 - 云服务器(阿里云/腾讯云等)务必进控制台检查「安全组规则」,确认入方向放行了对应端口(协议选
TCP,源 IP 如果是未知客户端,暂时设为0.0.0.0/0测试) - 本地开发用 VirtualBox / WSL / Docker 时,宿主机 windows/macOS 的防火墙常默认拦截外来连接;Windows 上临时关掉「Windows Defender 防火墙」或加入例外规则,macOS 查
pfctl -sr或系统偏好设置 → 防火墙 - 如果 Workerman 跑在 Docker 容器里,除了
-p 2345:2345,还得确认容器内监听的是0.0.0.0:2345,不是127.0.0.1:2345(后者在容器里也只响应 localhost)
Workerman 日志里没报错,但连接被静默拒绝?查 SO_REUSEADDR 和 TIME_WAIT
端口看似空闲,但系统还没彻底释放上次连接的 socket,新进程 bind 会失败,Workerman 却可能不报错、也不监听——此时客户端 Connection refused,但 ss -tuln 看不到端口,日志也干净。
- 启动前手动清理:先
killall php(或按 PID 杀掉所有 Workerman 进程),再ss -tan | grep :2345看是否有TIME_WAIT状态残留;大量存在说明连接频繁断开,需调优 - 在 Workerman 启动代码里显式设置
$worker->reusePort = true;(PHP 7.0+ Linux),避免端口争抢;老版本或 Windows 可设$worker->soReusePort = true;(需内核支持) - 别依赖
start.php restart,它只是 stop + start,stop 不一定杀干净;生产环境改用start.php stop && sleep 1 && start.php start更稳妥
客户端连上又立刻断开?检查协议握手和心跳逻辑
Workerman 默认是裸 TCP,客户端发数据前没做任何协议协商。如果客户端期望 http 握手、websocket 升级,或服务端开了 heartbeat_idle_time 但客户端没发心跳,就会秒断。
- 用
nc -v your-server-ip 2345手动连,敲几个字符回车——如果立刻断开,说明服务端代码里可能写了$connection->close()在onMessage外触发,或onConnect里抛了异常 - 检查
onMessage是否对非法数据直接return而没$connection->send(),某些客户端库会把无响应当成异常断连 - 若启用了心跳(
$worker->ping_interval = 30;),客户端必须每ping_interval - ping_not_response_limit秒内发一次任意数据,否则 Workerman 主动 close;调试阶段可先注释掉心跳相关配置 - wireshark 抓包看三次握手是否完成、SYN/ACK 是否返回、是否有 RST 包——这是绕过所有应用层日志的终极手段
真正卡住排查的,往往是“明明端口开着、日志没报错、telnet 也通,但就是连不上”。这时候得一层层剥:先确认客户端真实发出的 SYN 到了哪一层,再反推是防火墙拦了、路由丢了、还是 Workerman 根本没收到连接请求。别急着改代码,先让网络路径自己说话。