workerman启动长连接服务的关键是手动启动常驻内存的worker进程并调用worker::runall(),而非依赖php think run等传统方式;必须显式设置协议(如websocket://)、绑定onconnect/onmessage/onclose回调、实现心跳检测与连接复用逻辑。

Workerman 不是“装完就能跑”的 HTTP 服务框架,它不走 php think run 或 php -S 那套流程;长连接能力也不是靠 Composer 自动注入的——核心在于你手动启动一个常驻内存的 Worker 进程,并正确设置协议、回调与心跳逻辑。
Workerman 怎么启动一个真正的长连接服务?
关键不是“安装”,而是“启动一个不退出的 PHP 进程”。Workerman 的入口文件必须显式调用 Worker::runAll(),否则进程立即结束,根本谈不上长连接。
- 入口文件(如
start.php)里必须包含:require_once __DIR__ . '/Workerman/Autoloader.php';,然后创建Worker实例、设端口、绑回调,最后执行Worker::runAll() - 不能用
php start.php直接运行调试(会阻塞终端),要用php start.php start(需自己实现命令行参数解析)或配合php think worker http start(仅限 TP8 集成环境) - 监听协议必须明确:HTTP 长连接要写
http://0.0.0.0:8000,WebSocket 必须写websocket://0.0.0.0:2828,写成tcp://就只是裸 TCP,浏览器连不上 - Linux 下守护进程运行需加
-d参数,Windows 下建议用.bat脚本包装,避免窗口关闭导致进程终止
onConnect / onMessage / onClose 为什么必须全写?
漏掉任何一个,都会导致连接状态失控。尤其是 onClose 缺失时,Workerman 不知道连接已断,$connection 对象不会被释放,连接数持续增长直至内存耗尽。
-
onConnect:用于初始化连接上下文,比如记录客户端 IP、分配 session ID、设置$connection->lastMessageTime = time() -
onMessage:必须区分业务数据和心跳包(如收到"ping"就回"pong"),不能把所有数据都当业务逻辑处理 -
onClose:务必清理该连接关联的资源,例如从用户在线列表中移除、关闭其绑定的 Redis 订阅、释放临时缓存键 - 三个回调里的
$connection是同一个对象实例,它的属性(如id、remoteIp)在整个生命周期内有效,可跨回调使用
心跳机制怎么写才不掉连接?
单靠 Keep-Alive: timeout=60 HTTP 头没用——那是给反向代理或客户端浏览器看的,Workerman 本身不解析也不响应这个头;真正起作用的是你自己写的定时器 + 消息检测逻辑。
- 服务端定时器应独立于连接创建:在
onWorkerStart中用Timer::add(55, function () { ... })扫描所有连接,检查$connection->lastMessageTime是否超时(比如 >60 秒) - 客户端发送心跳频率必须小于服务端超时阈值,推荐 30–45 秒发一次
"ping",服务端 55 秒检测一次,留出网络抖动余量 - 不要在
onMessage里直接调用sleep()或阻塞 IO(如同步 MySQL 查询),这会让整个事件循环卡住,所有连接的心跳都收不到响应 - WebSocket 场景下,浏览器自动处理
PING/PONG帧,但 Workerman 默认不响应——需在onMessage中显式判断并回发,否则某些 CDN 或代理会主动断开
数据库/Redis 连接怎么复用不泄漏?
每个 Worker 进程只能持有一组后端连接,不能在 onMessage 里 new 一个新 MySQL 实例——那会迅速打爆数据库连接数。
- 在
onWorkerStart回调中初始化连接池,例如$mysql = new MySQL\Connection([...]),然后挂到全局变量或静态属性上 - Workerman 自带的
MySQL\Connection和Redis\Connection是非阻塞的,查询方法(如query())返回 Promise,必须用回调处理结果,不能用return或yield - 连接池大小默认是 10,高并发场景下需显式设
'pool_size' => 20,但也要匹配数据库最大连接数限制 - 别试图在
onClose里 close() 这些连接——它们属于 Worker 进程,生命周期与进程一致,强行 close 可能导致后续请求失败
最常被忽略的一点:Workerman 的“长连接”本质是 TCP 层的连接复用,它不自动解决应用层粘包、分包、协议解析问题。如果你用裸 TCP 传 JSON,就必须自己约定包头长度或换行符分隔;WebSocket 则由框架自动处理帧解析——选错协议类型,后面所有心跳、重连、数据解析都会出问题。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











