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