WebSocket断线后需客户端主动重连,服务端不负责重连;浏览器端应实现指数退避重连,PHP客户端需手动管理连接生命周期,且重连后须补全登录态或订阅逻辑。

WebSocket 断线后 onclose 触发但不自动重连
Workerman 的 Worker 本身不内置重连逻辑,onclose 只是通知连接已断,不会主动尝试重建 WebSocket 连接。客户端(浏览器或自研 client)必须自己实现重连机制,服务端无需、也不应“主动重连”——因为服务端没有“连接状态”的维持义务,它只响应请求。
常见错误现象:onclose 被触发后,客户端静默停止通信,用户以为“卡了”,其实是连接彻底丢失且未恢复。
- 重连必须由客户端发起,服务端只需保持
onMessage/onClose等回调稳定可用 - 不要在服务端用
$connection->send()前检查连接状态(Workerman 不提供isConnected()),它可能已断但连接对象仍存在 - 避免在
onClose中调用$connection->close()—— 此时连接已关闭,会触发警告
前端 JS 使用 WebSocket 实现带退避的重连
浏览器原生 WebSocket 对象断开后不可复用,每次重连都得新建实例。关键在于控制重试节奏,防止雪崩式重连请求打爆服务端。
示例逻辑(简化版):
let ws = null;
let reconnectTimer = null;
let retryCount = 0;
const maxRetries = 5;
const baseDelay = 1000;
<p>function connect() {
ws = new WebSocket('ws://your-domain.com:2346');</p><p>ws.onopen = () => {
console.log('connected');
retryCount = 0; // 成功则重置计数
};</p><p>ws.onclose = () => {
if (retryCount < maxRetries) {
const delay = Math.min(baseDelay * Math.pow(2, retryCount), 30000);
reconnectTimer = setTimeout(() => {
retryCount++;
connect();
}, delay);
}
};</p><p>ws.onerror = (err) => console.error('ws error:', err);
}
- 使用指数退避(
Math.pow(2, retryCount))比固定间隔更健壮 - 务必限制最大重试次数(
maxRetries),否则网络恢复前可能无限循环 - 不要在
onerror中直接重连——它可能在onopen前频繁触发,造成误判
PHP 客户端(如 Workerman 自建 client)重连需手动管理连接生命周期
如果你用 Workerman 写了一个 WebSocket client(比如做消息中继、设备代理),它不像浏览器有自动事件模型,必须显式轮询或监听 socket 状态。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
核心要点:
- 用
$client->isConnected()判断(Workerman 提供该方法),但注意它只是检查 socket 是否可写,不是最终通信保障 - 重连前先
$client->close(),再new Client(...),不能复用旧实例 - 在
onClose回调里启动重连定时器(用Timer::add()),别用sleep()阻塞进程 - 避免多个 client 实例同时重连:加锁或用全局标志位(如
static $isReconnecting = false)
服务端要不要做“心跳保活”?要看客户端是否支持
Workerman 默认不发 ping/pong,onWebSocketConnect 后连接就靠 TCP keepalive 维持。但很多 NAT 网关或代理会在 60–300 秒后静默断开空闲连接。
解决方案分两端:
- 客户端每 30 秒发一次
ping(文本帧"ping"或二进制空帧),服务端收到后忽略或回pong - 服务端可通过
$connection->ping()主动探测(需 Workerman ≥ 4.0.21),但别太频繁(建议 ≥ 45s 间隔),否则增加无谓负载 - 不要依赖
connection_timeout配置来“提前发现断连”——它只影响握手阶段,对已建立连接无效
真正容易被忽略的是:客户端重连成功后,往往没重新发送登录态或订阅主题。这部分业务逻辑(比如发 {"type":"auth","token":"xxx"})必须放在 onopen 后手动补全,Workerman 不帮你记上下文。

















