客户端连上后过一会儿断开,主因是公网nat/防火墙/dpi设备30–300秒空闲超时导致静默断连;需配置workerman服务端心跳(pinginterval=25s、pingnotresponseclose=60s),并禁用nagle算法、启用reuseport,同时用真实公网客户端复现验证。

客户端连得上但过一会儿就断,先看是不是空闲超时
公网链路里 NAT、防火墙、运营商 DPI 设备普遍有 30–300 秒空闲超时策略,连接没数据交互就会被静默 kill。Workerman 默认不发心跳,客户端发完一条消息后等半天再发第二条,中间链路早把 socket 给回收了——你看到的“断开”其实是 RST 包或无响应,不是 Workerman 主动关的。
必须手动开启服务端心跳:$worker->pingInterval = 25(每 25 秒发一次 ping),$worker->pingNotResponseClose = 60(60 秒没收到 pong 才关连接)。注意:这个 ping 是 Workerman 主动发的 WebSocket ping 帧,不是客户端定时发;如果客户端不回 pong,服务端才触发关闭。
- 某些 WAF 或 DPI 会拦截标准 ping/pong 帧,可改用业务层心跳,比如客户端每 20 秒发
{"type":"heartbeat"},服务端在onMessage里识别并重置连接活跃时间 - 别只在本地测:内网直连没 NAT,永远不超时;一定要用真实公网客户端(手机、远程服务器)复现
- WebSocket 协议下,
pingInterval仅对 WebSocket 连接生效;纯 TCP 不自带 ping,需自己实现
Worker 进程全挂了但日志没报错,重点查 exit status 256
看到 Worker[xxx] exit with status 256 就别翻业务日志了——这不是 PHP 异常,是子进程被内核强制终止(等价于收到信号 1 或段错误),workerman.log 里往往只有一行退出记录,后面啥都没有。
立刻执行:php -i | grep disable_functions,盯死 pcntl_fork、posix_kill、posix_getpid 是否被禁;再跑一遍官方检测脚本:curl -Ss http://www.workerman.net/check.php | php,它会直接告诉你哪些关键函数不可用。
-
display_errors=Off+error_reporting=0是默认配置,fatal error 全部静默,务必在start.php开头加:error_reporting(E_ALL); ini_set('display_errors', 'on'); - 确认
log_errors=On且error_log指向路径可写(df -h看磁盘是否满) - 用
ps aux | grep start.php确认 master 还在,但 worker 进程没了 → 基本就是onWorkerStart里抛了未捕获异常,去workerman.log最末尾搜Fatal error或Exception
ss -tuln 看不到监听端口,说明 Worker 根本没起来
很多人看到 Start success 就以为服务活了,其实只是 master 进程启动了,worker 因配置错、代码异常或权限问题压根没 fork 出来。最直接验证方式是查系统级监听状态:ss -tuln | grep :你的端口,有输出才说明内核真在监听。
如果只看到 127.0.0.1:2345 而不是 *:2345 或 0.0.0.0:2345,说明绑定的是回环地址,外部流量进不来——检查 new Worker('tcp://0.0.0.0:2345'),别写成 'tcp://127.0.0.1:2345'。
- 改完监听地址必须完整重启:
php start.php stop && php start.php start,reload不生效,旧配置还驻留在内存里 - 如果
ss无输出,再跑ps aux | grep WorkerMan:只有master process没有worker process→onWorkerStart报错了 - Docker 场景下,除了
-p 2345:2345,容器内也得监听0.0.0.0:2345,监听127.0.0.1:2345在容器里也只响应 localhost
客户端能连上、能收发,但偶尔丢包或突然断,查 Nagle 和 TIME_WAIT
高频小包场景下,Linux 内核默认启用 Nagle 算法(合并小包发),但公网链路中某一段缓冲区小或队列溢出,就容易丢包;同时短连接密集时 TIME_WAIT 堆积,新连接 bind 失败,Workerman 却可能不报错也不监听,表现为客户端 Connection refused 但 ss -tuln 看不到端口。
在 start.php 中为 Worker 显式禁用 Nagle:$worker->transport = 'tcp'; $worker->context = ['socket' => ['tcp_nodelay' => true]];;高并发长连接场景建议开启 reusePort:$worker->reusePort = true;,让内核分发连接到多个 worker 进程,缓解单进程压力。
- 检查系统参数:
net.core.somaxconn(连接队列长度)、net.ipv4.ip_local_port_range(本地端口范围),太小会导致连接失败 -
ss -s查看当前TIME_WAIT数量,若远超 3 万,考虑调大net.ipv4.tcp_tw_reuse - 别依赖
echo或var_dump()调试:输出位置不可控,容易被缓冲或混进系统日志;改用file_put_contents('/tmp/workerman-debug.log', "xxx\n", FILE_APPEND)
exit status 256 和 ss -tuln 无监听是最常被跳过的两步,一上来就改心跳或调参数,反而绕远路。











