0. 先交代一下背景
白天刚从发版流水线里爬出来,晚上回到终端,翻上一篇 AOI 那篇下面的评论区。有老哥问:
主策天天嚷嚷着要《街霸》一样手感,要 MMO 级大规模同屏、还要跟《瓦罗兰特》一样搞掉包和外挂防御,团队架构被“状态同步”和“帧同步”来回撕裂……这俩到底在服务端怎么选?
直接答应写个不背八股,专治带病选型的扫盲避坑文。网络模型不是“发包格式”这么浅,根本本质是你把物理世界“时间线裁决权”押在哪一侧。
不搞玄学外链图,只认原生 Mermaid,所有时序逻辑和顶级工业同步结构全部一把画满——黑夜白天都不炸的硬核大图 
1. 第一道门:根本世界观的碰撞(发车器 vs 时光机)
想想两种宇宙:
- 帧同步(Lockstep):服务端就是个“按时发车器”,只发计数包,不判断世界状态
客户端各自带着相同初始状态、收集来的输入,在自己小黑屋一集体算出来结果,理论上绝对一样。服务端只在每帧 Tick 收齐大家输入后广播出去,自己啥都不算。 - 状态同步(State Sync):服务端是“权威时光机”,只认自己内存里的状态世界,客户端上报的所有“意图”都要被判决加工,结果全以服务端为准,其它统统都是客户端自娱自乐。
参考 Glenn Fiedler 这张典型模型图 [S1]:
sequenceDiagram
autonumber
participant C1 as 客户端A
participant S as 服务端
participant C2 as 客户端B
rect rgb(240,248,255)
note over C1,C2: 帧同步 (Lockstep)
C1->>S: 操作输入(Frame=102)
C2->>S: 操作输入(Frame=102)
note over S: Tick对齐封包,打包广播,不跑物理
S-->>C1: 广播Frame数据
S-->>C2: 广播Frame数据
note over C1,C2: 客户端自行计算第102帧世界状态
end
rect rgb(255,245,238)
note over C1,C2: 状态同步 (State Sync)
C1->>S: 意图输入
note over S: 跑完整物理
S-->>C1: 下发状态快照/纠偏
S-->>C2: 发裁剪快照
note over C1: 如果预测偏差就回滚补正
note over C2: 插值/补间播放远程角色
end
> 💡 原则:帧同步传“因”(输入),状态同步传“果”(快照);谁能认定世界的“真理”,裁决权就在谁手里。
2. 第二道门:状态同步的工程骨架与三大深坑
市面主流射击/大逃杀/MMO 其实都用服务端权威状态同步 [S1],但能跑得顺的,必须搞定:
2.1 快照(Snapshot)与增量压缩(Delta Encoding)
不能死命每帧推全量树,带宽细分分分钟炸掉。最优做法:全量基线快照 + 增量环形基线。每链接自己追踪 LastAckedSequence,服务端按 Ack 做 Delta(全字段位掩码),未变的直接跳过。
2.2 客户端预测与纠错重演闭环
朴素模型下,输入到生效硬生生要走完整 RTT + 动画延迟,体验直线崩盘(比如100ms RTT + 100ms动画就是 200ms 迟滞)[S2]。
所以必须用客户端预测+对账重演闭环,直接 Mermaid 自绘完:
sequenceDiagram
autonumber
participant Client as 客户端
participant Server as 服务端
rect rgb(230,245,255)
Note over Client,Server: RTT+动画延迟=200ms硬延迟
Client->>Server: 输入(右键)
Note right of Server: 网络一程100ms
Server-->>Client: 权威位置x=11
Note right of Client: 网络回程100ms
Note right of Client: 动画播放100ms
Note right of Client: 总延迟=200ms
end
rect rgb(240,255,238)
Note over Client,Server: 预测+重演闭环
Client->>Server: #1(InputSeq=1)
Note right of Client: 本地立马预测
Client->>Server: #2(InputSeq=2)
Server-->>Client: 状态x=11,带确认#1
Note right of Client: 扔掉#1,只重演#2,保证收敛
end
> 💡 方法论:服务端包里带已处理序号,客户端重演未被权威确认的输入,永远不会乱飞。
2.3 延迟补偿:倒流时光 + 环形缓冲区(Lag Compensation)
如 CS/Valorant 这种快节奏射击必须在服务端做时间倒流 [S1][S4]。即,每实体存一段环形历史(1s左右),玩家开火带“射击时间”,服务端回滚所有目标的 Hitbox 状态到对应时刻,做射线判定。
——但副作用:你明明“进墙”了,服务端回溯看你还在旧坐标,所以就有经典“掩体后中枪”物理悖论。
工业标准都是回滚200ms内,超了就不认,防止老赖高延迟作弊。[S1]
3. 第三道门:帧同步的确定性地狱与回滚
常见于 RTS/MOBA/格斗(星际、王者、GGPO)。极省服务端算力,但要无条件锁死“完全一致”!
3.1 浮点灾难与定点数强制
不同平台浮点实现差别小数点后7位都会放大成画面乱飞灾难。必须全逻辑定点(Q32.32 或 Q48.16),所有参与同步的东西都整型表征,离线导表阶段处理完。[S1]
3.2 无序遍历、多线程 & PRNG 地狱
- 哈希表遍历必须全定序,有序字典/定序数组。
- 随机生成器专人专种 seed,逻辑层/表现层彻底剥离。
- 逻辑主循环必须单线程,不准乱调度。
3.3 逻辑帧/渲染帧解耦:Update & Lerp 插值
画面高刷必须插值展示,逻辑算出来N帧,渲染帧在前后一格间做Lerp,不然就是瞬移卡顿地狱。
3.4 现代帧同步救星:预测+Rollback
老式 Lockstep 木桶效应:只要一人卡全房间原地等。现代方案是丢包/延迟时直接预测,等真实输入包来再回滚-快进重演。
回滚要靠极小逻辑块和结构化内存快照,否则 mobile 端瞬间掉帧爆 GC。
4. 手术步骤与架构选型军规:一张思维决策网
别信玄学图片,原生 Mermaid 画工业级同步选型决策树,彻底拔掉透明外链。
flowchart TD
A["新项目网络同步选型"] --> B{"同局物理单位/实体数量级?"}
B -->|"几千~上万单位(RTS/MMO)"| C["确定性帧同步 (Lockstep)"]
B -->|"几十人/百人"| D{"是格斗/帧对抗还是大地图?"}
D -->|"格斗/强对抗/极短延迟"| E["预测回滚帧同步 (Rollback)"]
D -->|"射击/吃鸡/MMO"| F{"防外挂是否死线?"}
F -->|"必须严格服务端权威"| G["状态同步 (State Sync+LagComp)"]
F -->|"只要弱联网/无专服预算"| H["分布式权威/无服务端"]
C --> I["死磕定点/全平台一致/自定义公式"]
E --> I
G --> J["专服加逻辑倒流/高昂CPU成本"]
血泪避坑军规
军规 1:权威一律在服务端
任何带“结果”的封包(如 My_Position_Is)全当作弊,判定唯一靠自己内存树。
军规 2:帧同步断线重连必须有快照
DO NOT 刷全输入,工业级每15秒存快照,只补齐断点后操作重播。
军规 3:状态同步要有 fail-open 降级
预测崩就滑动阻尼/平滑过渡,连续断包时允许外推,不让主循环因为网络死锁。
军规 4:只认包层原始时序
排 Bug 必看原始十六进制,别信日志美化后内容,哪怕只差一个空格/序列号都能掉进去。
搞明白是谁裁决“真理”,工程才能不炸服、不掉大坑
😋
> 📚 参考来源:[Glenn Fiedler on Mas Bandwidth][S1], [Gabriel Gambetta][S2][S4]
[S1]: [redacted-url] [redacted-url] [redacted-url]
参考资料
- [S1] https://mas-bandwidth.com/choosing-the-right-network-model-for-your-multiplayer-game/(读取于 2026-10-24)
- [S2] https://www.gabrielgambetta.com/client-side-prediction-server-reconciliation.html(读取于 2026-10-24)
- [S4] https://www.gabrielgambetta.com/lag-compensation.html(读取于 2026-10-24)
评论 (0)