游戏网络进阶
概述
网络游戏把"单机逻辑"升级为"多端共识":所有客户端必须对游戏世界状态达成一致,同时保持交互低延迟。网络方案本质上是在三个目标之间做权衡——一致性(大家看到的一样)、实时性(响应快)、带宽(传输量小)。
| 方案 | 同步对象 | 带宽 | 一致性 | 典型游戏 |
|---|---|---|---|---|
| 帧同步 Lockstep | 输入 | 极小 | 强(确定性) | RTS、格斗 |
| 状态同步 | 游戏状态 | 较大 | 中(可容忍偏差) | FPS、MMO |
帧同步(Lockstep)
原理
所有客户端只同步输入,不同步状态。逻辑层是确定性的:同一组输入按相同顺序执行,必然得到相同结果。游戏被切成固定步长的"帧"(Tick),每个 Tick 内所有玩家先提交输入,再统一推进一帧逻辑。
text
Tick N-1 Tick N Tick N+1
玩家A 输入 →┐
玩家B 输入 →┼→ 确定性模拟 → 世界状态 → 渲染
服务器确认 →┘确定性模拟的要求
- 固定步长:逻辑必须按固定时间步长推进(1/60 秒),不能依赖帧率
- 纯函数逻辑:不使用 Math.random()(改用确定性伪随机种子)、不使用浮点比较差异(不同平台舍入不同)
- 输入序列一致:所有客户端按相同顺序处理输入,包括"空输入"也要作为一个 Tick 广播
优缺点
- 优点:带宽极小(每秒只传几次输入包);回放容易(记录输入序列即可);天然反作弊(逻辑在客户端也难篡改出优势,除非改内存)
- 缺点:全体玩家以最慢者的速度推进(一个人卡顿,所有人卡顿);断线/加局处理复杂;对确定性要求苛刻
状态同步(Snapshot Sync)
原理
服务器拥有权威世界状态,按固定频率(如 10~20Hz)向客户端广播状态快照;客户端不直接"运行"服务器逻辑,而是接收快照并渲染。客户端体验到的移动是"采样 + 插值"的结果。
text
服务器: world(state) ──每100ms──→ 状态包 ──→ 客户端A/B
↓
客户端在包之间插值补间插值与延迟补偿
客户端收到的是离散状态点,直接渲染会一跳一跳。解决手段:
- 插值(Interpolation):在最近两个包之间按时间线性插值位置,画面平滑但比服务器滞后一个包周期
- 预测(Prediction):本地方块直接响应用户输入,不等服务器确认,减少操作延迟
- 回滚(Reconciliation):服务器权威位置到达后,若与预测不符则回滚修正(纠偏)
优缺点
- 优点:响应快(本地预测);单端掉线不影响他人;服务器权威,易防作弊
- 缺点:带宽大(状态包体积 × 频率);存在"看到了别人的过去"的延迟感知
对比演示
下面的示例用同一个确定性轨迹对比两种同步方式:帧同步下本地(绿)与远端(蓝)完全重合——因为输入同步、确定性模拟;状态同步下服务器状态包(红点)每 100ms 采样一次,客户端(蓝块)在包之间插值移动,拖动"网络延迟"滑块可以直观看到延迟越大、客户端滞后越明显:
TCP 与 UDP 选型
| 维度 | TCP | UDP |
|---|---|---|
| 可靠性 | 保证到达且有序 | 不保证,可能丢包/乱序 |
| 延迟 | 丢包触发重传,延迟高 | 无重传开销,低延迟 |
| 头部开销 | 大 | 小 |
| 适用 | 登录、聊天、存档、任务数据 | 实时位置、状态快照、语音 |
游戏网络的经典分工:可靠数据走 TCP 或"UDP 上的可靠层"(KCP/QUIC 等),实时数据走纯 UDP。重传只针对关键消息(玩家加入、装备变更),位置快照丢了就丢了——下一包很快会来。
防作弊
- 权威服务器:一切关键数值(血量、伤害、掉落)由服务器计算,客户端只上报输入
- 确定性校验:帧同步游戏中,服务器可随机抽取 Tick 回放校验客户端结果是否一致
- 数据校验:对状态包做哈希/签名,防止客户端篡改
- 行为分析:检测异常高频请求、瞬移、超常数值,标记可疑玩家
断线重连
断线重连的关键是让客户端能"接续"服务器上的会话:
- 会话 ID 恢复:客户端重连时带上旧会话 ID,服务器恢复该玩家的身份与位置
- 状态快照:服务器定期保存玩家关键状态(位置、背包、进度),重连后下发
- 增量同步:重连后先同步全量快照,再切回增量更新,避免长时间断线的巨大差异
- ID 映射:重连后本地的实体 ID 与服务器实体 ID 重新绑定
js
// 重连流程:恢复会话 → 拉快照 → 增量订阅
client.reconnect(sessionId, () => {
const snapshot = server.getSnapshot(playerId) // 全量状态
world.applySnapshot(snapshot)
client.subscribeIncremental() // 切回增量更新
})方案选型速查
| 游戏类型 | 推荐方案 | 理由 |
|---|---|---|
| RTS / 格斗(操作数少、强公平) | 帧同步 | 带宽小、回放方便 |
| FPS / MOBA(操作密集、低延迟) | 状态同步 + 预测 | 响应快、易防作弊 |
| 休闲 / 社交(弱实时) | 状态同步 + 低频率 | 带宽可控、实现简单 |
| 大型 MMO | 状态同步 + 分区分服 | 扩展性优先 |