1406 words
7 minutes
Game_webSocket
一、一张图看懂 HTTP、SSE、WebSocket 的区别
HTTP:你问一次,我答一次
客户端 ────请求────> 服务端客户端 <────响应──── 服务端 [连接关闭]SSE:我只听,不说话
客户端 ────请求────> 服务端客户端 <────数据1──── 服务端客户端 <────数据2──── 服务端客户端 <────数据3──── 服务端 [连接保持,但客户端不能发消息]WebSocket:随时聊,聊多久都行
客户端 ────握手────> 服务端客户端 <───握手成功─── 服务端 [连接保持]客户端 ────消息A───> 服务端客户端 <───消息B──── 服务端客户端 ────消息C───> 服务端客户端 <───消息D──── 服务端对比表
| HTTP | SSE | WebSocket | |
|---|---|---|---|
| 谁可以主动说话 | 只有客户端 | 只有服务端 | 双方都可以 |
| 连接像什么 | 打电话,说完就挂 | 听收音机,只能接收 | 拉微信群,随时聊 |
| 小程序能用吗 | ✅ | ❌ | ✅ |
| 做什么用 | 普通接口 | 服务端推送 | 聊天、AI对话 |
二、核心概念:连上只是第一步
WebSocket 的连接不是一个简单的开关,它有 4 个阶段:
[未连接] ──调用connect──> [连接中] ──TCP通了──> [已连接] ──认证成功──> [可用] ↑ │ └──────────────────── 断线自动重连 ──────────────────────┘关键点:已连接 只代表网线插上了,可用 才代表业务能用(比如用户登录验证通过)。
三、最简示例:5 行核心代码
// 小程序端const socket = wx.connectSocket({ url: 'wss://your-server.com' })
socket.onOpen(() => socket.send({ data: 'Hello' }))socket.onMessage(res => console.log('收到:', res.data))这就是 WebSocket 的本质。其他所有东西(心跳、重连、认证)都是为了让它在真实网络环境里稳定运行。
四、工程化四大问题及解法
问题1:怎么知道连接还活着?
场景:用户把手机放兜里,App 在后台,连接可能已经被系统切断了。
解法:心跳
[客户端] 每30秒 ──ping──> [服务端][服务端] <──pong── [客户端]
如果10秒没收到pong → 认为连接断了 → 触发重连问题2:断线了怎么办?
场景:用户进电梯,信号断了。
解法:指数退避重连
第1次断线 → 等1秒重连第2次断线 → 等2秒重连第3次断线 → 等4秒重连...最多等30秒为什么要这样?如果 1000 个用户同时断线,同时重连,服务器会被打爆。
问题3:重连后消息丢了怎么办?
场景:断线期间服务端发了 3 条消息,客户端没收到。
解法:记住”读到哪里了”
客户端记录:session_123 我已经收到第5个分片了
重连时告诉服务端:我收到第5个了服务端:那就从第6个开始发问题4:怎么让业务代码不关心连接细节?
解法:发布-订阅模式
// 连接层只管连接和分发ws.onMessage(msg => emit(msg.type, msg.data))
// 业务层只管订阅ws.on('stream_chunk', data => 拼接内容)ws.on('game_status', data => 更新进度)这样,新增一个消息类型只需要加一行 ws.on(...),不用改连接层的代码。
五、完整的连接管理架构
┌─────────────────────────────────────────────────────────┐│ 业务层 ││ on('stream_chunk') on('game_status') on('reply') │└─────────────────────────────────────────────────────────┘ ▲ │ emit(event_type, data)┌─────────────────────────────────────────────────────────┐│ 事件分发层 ││ 根据 event_type 调用对应的业务回调 │└─────────────────────────────────────────────────────────┘ ▲ │ 解析消息┌─────────────────────────────────────────────────────────┐│ 连接管理层 ││ ├── 连接/重连 ││ ├── 心跳保活 ││ ├── 认证 ││ └── 网络状态监听 │└─────────────────────────────────────────────────────────┘ ▲ │ 收发数据┌─────────────────────────────────────────────────────────┐│ 微信 WebSocket API │└─────────────────────────────────────────────────────────┘六、实际业务流程:AI 对话
1. 用户输入"你好" │ ▼2. 界面立即显示用户消息(pending 状态,灰色) │ ▼3. WebSocket 发送 { type: 'chat', content: '你好' } │ ▼4. 服务端返回 stream_chunk(一个字一个字地推) ┌─────────────────────────────────────────┐ │ chunk1: '你' │ │ chunk2: '好' │ │ chunk3: '呀' │ │ chunk4: '!' │ └─────────────────────────────────────────┘ │ ▼5. 客户端边收边拼,界面上一个字一个字冒出来 │ ▼6. 收到 stream_done,结束流程图
用户 ──发送消息──> 小程序 ──WebSocket──> 服务端 │ │ stream_chunk(你) ▼ 界面更新("你") │ │ stream_chunk(好) ▼ 界面更新("你好") │ │ stream_done ▼ 标记完成七、什么时候用,什么时候不用
✅ 用 WebSocket
| 场景 | 为什么 |
|---|---|
| AI 对话 | 需要服务端主动推流式内容 |
| 游戏状态推送 | 需要实时更新进度 |
| 协作编辑 | 需要双向同步 |
❌ 不用 WebSocket
| 场景 | 用什么 |
|---|---|
| 获取用户信息 | HTTP GET |
| 提交表单 | HTTP POST |
| 列表分页 | HTTP + 缓存 |
判断标准
需要服务端主动推送消息? ├── 是 → 需要长连接 │ ├── 我也要发消息 → WebSocket │ └── 我只收不发 → SSE(小程序不支持,还是WebSocket) └── 否 → HTTP 就够了八、代码结构(最小可用版)
class WsManager { constructor(url) { this.url = url this.handlers = new Map() // 事件名 → 回调函数数组 }
connect() { this.socket = wx.connectSocket({ url: this.url })
this.socket.onMessage((res) => { const { event_type, data } = JSON.parse(res.data) this.emit(event_type, data) // 分发给订阅者 })
this.socket.onOpen(() => this.send({ event_type: 'auth', token: getToken() })) }
on(event, callback) { if (!this.handlers.has(event)) this.handlers.set(event, []) this.handlers.get(event).push(callback) }
emit(event, data) { (this.handlers.get(event) || []).forEach(fn => fn(data)) }
send(data) { this.socket.send({ data: JSON.stringify(data) }) }}
// 使用const ws = new WsManager('wss://your-server.com')ws.connect()
ws.on('stream_chunk', (data) => { this.setData({ content: this.data.content + data.content })})
ws.on('stream_done', () => { console.log('对话完成')})总结(4 句话)
- HTTP 是问一句答一句,WebSocket 是拉群聊,随时都能说话
- 连接有 4 个状态,只有”可用”才算真正能用
- 生产环境必须加:心跳、重连、状态恢复
- 业务层用发布-订阅,连接层和业务层解耦
Game_webSocket
/posts/2026-6-7/game_websocket/ Some information may be outdated