跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

如何使用Workerman实现大屏数据实时推送?

Workerman本身不内置自动广播或分组推送逻辑,仅提供基础WebSocket帧收发;需自行实现连接状态跟踪、screen_id标识、心跳保活及离线消息补发机制,否则易导致大屏掉线、数据不同步和性能瓶颈。 Workerman 本身不内置 WebSocket 服务端的“自动广播”或“按分组推送”逻辑,你得自己搭好连接管理 + 消息路由,否则大屏刷新会卡、掉线、数据不同步。 为什么直接 new Worker('websocket://0.0.0.0:2346') 不够用? 单纯启动一个
Worker
实例只负责收发原始帧,没有连接状态跟踪、没有客户端分组、没有心跳保活——大屏页面一旦刷新或网络抖动,
onClose
不触发、连接残留、新连接无法继承旧状态。更麻烦的是:你没法区分哪个消息该推给哪块屏。 实操建议: 必须用
WebsocketConnection
的
$connection->id
或自定义
$_SESSION
(配合
Session
扩展)标识每个大屏终端 用全局数组或
Redis
存储“屏ID → connection 对象”的映射,避免用
foreach($worker->connections)
全量遍历(连接数一过百就明显延迟) 在
onConnect
里解析 URL 查询参数,例如
wss://api.example.com?screen_id=dashboard-01
,提取
screen_id
并绑定到
$connection->screen_id
如何安全地向指定大屏推送 JSON 数据? Workerman 的
$connection->send()
只接受字符串,但大屏前端通常 expect
JSON
。直接
json_encode($data)
发送没问题,但要注意三件事: 必须检查
$connection->isConnected()
再 send,否则可能触发 warning:“trying to write on closed connection” 避免在
onMessage
里直接
sleep()
或阻塞 IO(比如同步查 MySQL),会导致整个进程卡住;改用
AsyncTcpConnection
或
MySQLi::queryAsync
(需 workerman /mysql) 如果推送频率高(如每秒 10+ 条),启用
$connection->enableSSL = true
前务必确认证书链完整,否则 Chrome 会静默断开 wss 连接且不报错 示例片段:
// 推送前校验 if ($connection->isConnected() && isset($connection->screen_id)) { $connection->send(json_encode(['type' => 'stats', 'data' => $payload], JSON_UNESCAPED_UNICODE)); }
怎么让 50+ 大屏稳定长连不掉线? 默认配置下,Nginx、SLB、甚至某些企业防火墙会在 60 秒无数据时主动踢掉 TCP 连接。Workerman 不自动发 ping/pong,得手动加心跳。 在
onConnect
设置定时器:
$connection->pingTimer = Timer::add(25, function() use ($connection) { $connection->send('{"type":"ping"}'); });
在
onMessage
里拦截
ping
/
pong
,并重置连接活跃时间(Workerman 本身不维护 lastActiveTime,得自己记) Linux 内核参数要调:
net.ipv4.tcp_keepalive_time = 300
(不能依赖它,仅作兜底) 禁用
Worker::$daemonize = true
时的
max_connections
默认值(2048),改用
Worker::$maxConnections = 10000
并配好 ulimit -n 真正难的不是推一条数据,而是当某块屏断网重连后,如何补发它离线期间的 37 条关键指标更新——这需要你在推送前把变更写入
Redis Stream
或本地
leveldb
,并在重连时按
screen_id
拉取未读事件。这个环节没人替你做。

相关文章