Webman需自行实现用户在线状态监控,核心是可靠判定“还在线”:通过手动心跳(ping/pong)、Redis统一存储(避免内存不一致)、onClose清理状态、防重复连接及Redis故障兜底。

Webman 本身不提供开箱即用的用户在线状态监控能力,必须自己实现连接生命周期管理、状态存储与跨进程同步——核心难点不在“连上”,而在“怎么可靠判定‘还在线’”。
WebSocket 连接必须手动维护心跳和超时清理
Webman 的 onMessage 回调默认不处理 ping/pong,前端发来的 ping 若不响应,连接会静默断开,但服务端仍认为用户“在线”。
- 在
app/process/WebSocket.php的$ws->onMessage中显式判断:if ($msg['type'] === 'ping') { $connection->send(json_encode(['type'=>'pong'])); return; } - 前端需定时(如每 25 秒)发送
{"type":"ping"},并监听onclose触发指数退避重连(例如 1s → 2s → 4s) - 服务端不要主动调用
$connection->close()来“踢人”,应只依赖onClose回调触发状态清理——这是唯一可信的断连信号 - 避免多个标签页重复连接同一用户 ID,建议在
onOpen里用$connection->id绑定user_id,并查 Redis 是否已存在该用户活跃连接,有则先close旧连接
状态不能存在内存或 $_SESSION,必须用 Redis 统一存储
Webman 是多 worker 进程模型,写入单个进程内存或 $_SESSION(默认文件驱动)会导致状态不一致:A 进程标记用户上线,B 进程查不到,前端看到“掉线”。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 用 Redis 的
SET user:123:online "1" EX 30存在线标识,TTL 设为略大于心跳间隔(如 30 秒) - 在
onOpen中执行redis()->set("user:{$uid}:online", 1, ['EX'=>30]);在onClose中del("user:{$uid}:online") - 查询“某用户是否在线”时,统一走
redis()->exists("user:{$uid}:online"),不要查本地变量 - 若需批量查在线用户列表,用
keys user:*:online风险高(阻塞、慢),改用 Redis Set:sadd online_users 123+expire online_users 30,但要注意 Set 不自动过期,得靠 TTL key 或定时任务清理
避免告警风暴和状态误判的三个关键点
真实场景中网络抖动、NAT 超时、浏览器休眠都会导致短暂断连,直接当“下线”处理会引发误通知或 UI 频繁闪烁。
- 前端重连成功后,别急着发“上线”事件——先等服务端确认旧连接已
onClose,再发新连接的user:123:joined消息,否则可能双端状态不同步 - Redis 的
EXPIRE不是精确计时器,受 Redis 负载影响可能延迟几秒过期;若要求强实时,需额外起一个定时任务扫描user:*:online并比对最后心跳时间戳 - 不要用
connection->getRemoteIp()做用户去重依据——代理、CDN 下 IP 不稳定;始终以登录态中的user_id为准,且该 ID 必须在 WebSocket 握手阶段(如 URL query 或 token)完成校验并绑定
最易被忽略的是:Redis 连接故障时,onOpen 写入失败不能静默吞掉,必须记录错误日志并拒绝连接——否则用户以为连上了,实际状态根本没落地。状态存储层一旦不可用,整个在线逻辑就失效,这点比业务逻辑本身更关键。

















