跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

Swoole高频WebSocket功能_Swoole WebSocket应用技巧【说明】

WebSocket自动重连需客户端实现指数退避重连,服务端配合连接去重、心跳保活及Redis映射用户ID与fd;推送前须校验fd有效性,批量推送应分片+协程让渡或投递task进程处理。 WebSocket连接断开后怎么自动重连 客户端主动断开或网络抖动导致
onClose
触发,但服务端不会自动重连——这是常见误解。Swoole 的 WebSocket 服务端本身不管理重连逻辑,必须由客户端控制。 实际做法是:前端监听
onclose
,延迟几秒后调用
new WebSocket(url)
;服务端需配合做连接去重和心跳保活。 不要在服务端写“重连代码”,那是客户端的事 客户端首次连接失败时,建议指数退避(如 1s → 2s → 4s),避免雪崩式重连 服务端若未正确处理重复
onOpen
(比如用户快速刷新页面),可能导致
fd
冲突或 session 错乱 务必在
onOpen
中校验 token 或 session,否则重连可能绕过鉴权 如何安全地给指定用户推送消息(不是广播) 直接用
$server->push($fd, $data)
是最常用方式,但前提是得知道目标用户的
fd
。问题在于:
fd
是连接级标识,每次重连都会变,不能当用户 ID 用。 典型错误是把
fd
存数据库或当长期凭证传给前端——这会导致推送失效或信息错发。 登录成功后,服务端应将
fd
映射到业务用户 ID(如
user_id_123
),存在 Redis 哈希表里:
HSET user_fd_map 123 17
用户登出或
onClose
时,必须立刻
HDEL user_fd_map 123
,否则会推送给已断开的连接 推送前先
HGET user_fd_map 123
查
fd
,再用
$server->exist($fd)
确认连接还活着,避免
push
报
invalid fd
别用数组存
fd
映射,高并发下 PHP 数组不是线程安全的,Redis 才可靠 心跳超时设置不对,连接被悄悄断开 Swoole 默认不启用心跳检测,
onMessage
不触发不代表连接还活着。很多线上问题表现为“用户突然收不到消息”,其实是 TCP 连接被中间设备(如 Nginx、防火墙)静默关闭了。 Swoole 6.1.1 Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。 下载 根本解法是开启 Swoole 层心跳,并合理设置参数: 在
Server
配置中加:
'heartbeat_idle_time' => 600
(单位秒,表示 10 分钟没数据就踢掉) 同时设
'heartbeat_check_interval' => 60
(每 60 秒扫一次,值太小增加 CPU 负担) 前端必须实现 ping/pong 心跳,且间隔要小于
heartbeat_idle_time
,建议设为 30s 别依赖浏览器
WebSocket
自带的底层心跳——它不可控,也收不到通知 如果用了 Nginx 反向代理,还得配
proxy_read_timeout 600
,否则 Nginx 先断连 并发推送大量消息时卡顿甚至崩溃 直接在一个
foreach
里循环调用
$server->push()
推送几千人,大概率触发协程调度阻塞或内存暴涨。Swoole 的
push
是同步写 socket,不是发完就完。 本质是 I/O 密集型操作没做节流,容易拖垮整个 EventLoop。 单次推送不要超过 50 个
fd
,用
array_chunk
拆分批次,每批后
co::sleep(0.001)
让出协程 避免在
onMessage
或
onReceive
中做大批量推送,应投递到 task 进程处理:
$server->task($data)
task 进程里推送时,仍要检查
$server->exist($fd)
,因为
fd
可能在 task 执行期间已断开 如果消息体很大(如 >64KB),考虑压缩或分片,否则可能触发
send buffer full
错误 真正难的不是怎么推,是怎么推得稳——连接状态瞬息万变,所有
fd
相关操作都得带存在性校验,漏一次就可能引发连锁异常。

相关文章