腾讯游戏学院 第十章 网络同步技术 学习打卡
同步
-
一致性
-
及时性
-
鱼和熊掌的关系
输入模块
- = 函数输入
核心逻辑模块
- 函数
输出控制模块
- 函数输出
输出模块
- 画面
定点数
- 以32位定点数为例
- 内部的原始表示方式为32位整数
- 基于定点数的四则运算
- 用整数运算来实现定点数的运算
- 基于定点数的开方及超越函数
- 多项式拟合、迭代法、查表法等
- 基于定点数的随机函数
如何得到一致性的逻辑及对应的状态
- 保持客户端的版本一致
- 不要依赖不确定性的外部逻辑(比如UI交互逻辑)
- 限制外部逻辑(比如UI交互逻辑)对核心逻辑的调用
- 谨慎使用多线程
简介
- 同步状态数据
- 易上手难维护
- 核心处理模块结构
- 单点计算
- 直接把用户输入数据传到服务器,服务器做完之后,把状态同步到各个客户端,达到状态一致,非常简单也非常粗暴
- 分布式计算
- 由每一个客户端分别去负责某一部分核心逻辑的运算,然后再把我负责运算的一些状态传到客户端,其他客户端也把它们负责运算状态传给我
- 单点计算
冲突问题
-
仲裁权
- 多方竞争仲裁权
-
强一致性
- 冲突避免
-
弱一致性
区分核心/非核心一致性
- 是否影响核心博弈结果
- 核心一致性
- 仲裁单点化异步交互
- 非核心一致性
- 仲裁分散化延迟同步
- 核心一致性
游戏类型 | 核心一致性 | 非核心一致性 |
---|---|---|
赛车 | 冲线 道具(拾取/使用/命中) | 位置 赛道碰撞 … |
射击游戏 | 射击命中 装备 … | 位置 移动物理 … |
三消 | 分数 攻击干扰 … | 对手棋盘状态 对手操作 … |
-
应用场景 - FPS
-
操作响应延迟敏感
-
核心仲裁(命中)延迟不敏感(相对)
- 数据仲裁权独立划分
- 一致性有容错空间
- 物理、3D运算复杂
- 吃鸡中的射击命中,对延时不敏感
- 客户端自行处理射击逻辑,再通知服务器计算子弹轨道和命中结果,再发回给客户端
-
帧同步
- 以固定频率同步玩家的下一帧的操作
优势
- 服务器逻辑简单,负载低
- 整体研发周期缩短
- 表现一致性高
- 同步流量小,带宽成本低(把更新操作规定在每帧内,时间往往很短,那么对玩家来说用户输入量不会太多)
缺点
- 反外挂问题严峻
- 网络延时敏感度高
- 不同步问题较难定位和解决(每一步的同步正确与否,取决于上一步必须正常同步)
应用场景
适用于:
- 单局规模适中
- 不会中途加入角色
- 实时性要求较高
比如:
- ACT:火影忍者手游
- FTG:拳皇命运
- SPG:NBA2K Online
- RTS:WarCraft、StarCraft
- ARTS/MOBA:王者荣耀
状态同步
优势
- 小规模状态/可划分子系统(非常容易实现)
- 计算量小,我只负责我本地的一些逻辑运算,服务器不需要计算复杂的物理,或是玩家自己仲裁一些变量状态的计算
- 输入延迟小
- 技术门槛低
劣势
- 大规模状态(同步数据大)
- 流量(相对于帧同步有明显的劣势)
- 分布式计算/复杂逻辑一致性(很难去协调)
- 后期维护成本高
常用品类
- 射击
- 赛车
- 三消休闲
- 对操作延时很敏感,或对操作延时或者状态延时不敏感的一些品类
及时性问题的通用解决方案
协议选择
- 在弱网络(移动网络)的情况下
- 使用TCP还是UDP呢
网络环境 | TCP平均延迟 | RUDP平均延迟 | 结论 |
---|---|---|---|
网络良好 | 133 | 100 | RUDP略优 |
5%丢包 | 173 | 143 | RUDP略优 |
50%丢包 | 262 | 115 | RUDP优势明显 |
50ms抖动 | 198 | 130 | RUDP优势明显 |
总体来看,UDP在保证可靠性的前提下,对弱网络的延迟表现仍好于TCP
RTT:Round Trip Time
- 发送端发送一个【数据包】到收到接收端【应答的ACK】,所耗时的时间

RTO:Retransmission Timeout
- 重传超时时间。即,发送端发送一个【数据包】,等待RTO时间猴没有传到ACK,便会重发之前的数据包

最小丢包延时
- 当丢包发生时(假设只丢一次包),接受方最终收到发送的【数据包】的最小耗时

两种实现可靠UDP的原理
- 基于ARQ(自动重传请求)原理
- 最小丢包延时=2RTT
- 一般首次RTO=1.5RTT

- 发送了M1、M2、M3、M4后如何处理重传有三种(等待式/后退N步/选择重发)
- 等待式:(对带宽是一种浪费)

- 后退N步:若M3丢包,B无法确认该包,A就会启动对M3的超时重传,A会把之后的包全部重传,B一旦发现M3没有收到,会将后面的所有包进行丢弃(对网络通信信道的浪费(通道过于拥挤))

- 选择重传:将M4、M5缓存起来

- 基于FEC(前向冗余纠错)原理
- 最小丢包时延=0.5RTT+FT
- 一般FT为33MS或者66MS
- 远少于RTO
- FEC的最小丢包时延远少于ARQ的最小丢包延时

使用ARQ还是FEC
优点 | 缺点 | |
---|---|---|
ARQ | 算法应用场合广泛 有大量现成的实验方案 比如KCP | 最小丢包时延较高 =1.7~2*RTT |
FEC | 最小丢包时延较低 <=1.5*RTT | 算法复杂 局限于帧同步 没有现成的实验方案 |
UDP分组优化
- IP分片 - 重组
- 当UDP大包在网络链路上传输的时候,如果链路的MTU大于UDP包的大小,那么系统就会将这个UDP大包,拆分成一个个IP包进行发送,接受方再对这些IP重组,如果任何一个IP包丢了,系统就会认为整个UDP包丢了
- 避免UDP包的大小超过链路层的最小MTU
- 以太网:1500-20-8=1472
- 英特网:576-20-8=548
- 还有可能存在的各种子网
- 经验最佳MTU:470Bytes
网络方案
丢包优化
相关性丢包
- 原因:
- 链路拥塞
- 路由器负载过高
- 无线信号衰减
- 基站&场景切换
- 特点:
- 它有原因(有一些相关指标影响)的(程序员一般无能为力)
随机性丢包
- 原因:
- 二进制信道噪音
- 特点:
- 无规律,随机出现
- 据数据统计,89%的丢包都属于这种
Gilbert Model(吉伯特模型)
- 连续丢掉k个包的概率
- 对同一个包,连发2次,2次不够,就发3次,直到将MTU填满
对时
- 对齐时间轴
- 帧同步:第一帧
- 状态同步:所有状态(每个状态带上对齐后的时间戳)
预表现
- 帧同步时,玩家的输入到服务器接收,再返回来,中间阶段没有处理输入数据,本地玩家需要怎么表现呢?(需要一个预表现的行为)
- 状态未到,表现先行
- 预测
- 插值
- Dead Reckoning
利用常量或惯性量
- 规则层面
- 人为设置
- 无用户输入
- 硬直(状态机确定状态)
- 用户输入
- 人的手速有限
- 寻找积分导数