|
前言
多人在线游戏挑战
网络协议
TCP/IP协议

两台电脑怎么交互呢?
网络传输介质:电缆、光纤、Wifi

解决方案:中间件

OSI模型
7层,分层复用

Socket
socket的英文原义是“插座”
socket非常类似于电话插座。
以一个电话网为例:电话的通话双方相当于相互通信的2个程序,电话号码就是ip地址。
通话双方各买一个电话(初始化Socket),拨打电话进行连接(connnet),挂上电话结束通信(Close)


TCP(Transmission Control Protocol)
- 面向连接的
- 稳定、有序
- 流量控制
- 拥塞控制(网络拥塞,降低发包速度)
TCP包头

TCP重传机制
- 正常发包1,2,3,4,5,6,7,8,收包都会带一个ACK序号,收包1,2,3,4,5,6,7,8
- 如果5号包丢了的话,那么收到的就是1,2,3,4,4,4,4,4

TCP拥塞控制
滑动窗口 UDP(User Datagram Protocol)
UDP包头


现在一看,TCP有点像封装后的UDP,有点像Unity的Animation系统相较于PlayerableAPI。
要高自由度的话,可以在原始UDP上进行自定义,或者TCP,UDP混用
我们为啥要自定义协议?
- 因为有多种需求:
- 游服
- 心跳(TCP)
- 保持逻辑有序(TCP)
- 高反应&低延迟(UDP)
- 广播消息(UDP)
- Web服务器
- HTTP协议
- 请求静态资源(文本、图片、链接、文件、视频)
ACK&序列号
- ACK(Acknowledgment):一个在通信双方传递,用来表示已经收到消息的标识。
- NAK(Negative Acknowledgment)
- SEQ(Sequence number):一个用来追踪发送消息的计数器
- Timeouts:超时时长
- ARQ(Automatic Repeat Request):自动重传机制,如果等待超时或者丢包,就自动重发数据
- 活动窗口协议的不同策略
- Stop and Wait ARQ:滑动窗口长度为1,发一个,等收包,再发下一个
- Go back N ARQ:N是窗口长度,一个ACK没收到,把窗口内的包重发一遍
- Selective Repeat ARQ:只重传丢ACK的包,收到一个坏包就用NAK
FEC(Forward Error Correction)算法:UDP丢包处理
- XOR FEC
- 异或算法。
- 发包的时候,多发一个要发的包的异或值。
- 只能最多丢一个包,用其他包的异或,能算出丢包的值
- Reed-Solomon Codes
怎么自定义基于ARQ和FEC的UDP?
- 使用Selective Repeat ARQ
- 使用FEC算法用来做丢包的错误矫正
时钟同步&RPC
RTT(Round Trip Time)
RTT是从发一个包到收到这个包的回包的时间延迟
RTT和Ping的区别,用的协议不一样

网络时间协议(Network Time Protocol,NTP)
用来同步计算机时间 Reference Clock

NTP算法

假设收发的延迟时间是一样的,我们可以得到以下的Offset

那么本地的时间就矫正为

RPC(Remote Procedure Call)

IDL(Interface Definition Language)
比如谷歌的protobuf

RPC Stubs
我的理解是一个中间层,RPC都通过这个中间层去处理

RPC的流程
- 建立连接:会话id,加密信息,压缩信息,秘钥
- 发送消息:压缩、加密、传输,收到后进行解密,解压缩
- 断线重连:会话id,token

网络拓扑

P2P

P2P 有主机服务器版

专用服务器
游戏同步
快照同步
- 客户端上传输入
- 服务端根据输入模拟计算状态,把整个世界的快照同步下去
- 客户端按照快照进行渲染
快照同步优化:
- 不变的不同步,只同步变化的。有个致命问题,丢包就崩了
优缺点:
- 客户端算力浪费
- 服务端压力大
- 带宽需求大,需要同步的数据太多
帧同步
- 相同的输入+相同的帧率 = 相同的状态模拟
- 客户端上传输入,服务端把所有输入下发,客户端模拟渲染
严格帧同步可能出现的问题
网速卡的会卡住大家进程 怎么处理?
Bucket同步,固定时间(100ms)收集输入上传,不管是否收到所有玩家的输入 我们需要根据实际项目,权衡用哪种同步,
保证一致输出的前提
- 浮点数
- 符合IEEE 754标准?
- 不同平台的实现不同,需要保证一致
- 定点数数学库
- Look-up table
- 随机数
- 排序算法
- 数学库
- 物理模拟
- 逻辑执行顺序
定位和Debug
CheckSum,自动定位问题

延迟(Delay)和抖动(Lag)处理

重连和追帧
- 客户端快照:一段时间,存个整个世界的快照,存到硬盘里,断线重连的时候,找到最近的快照,从这个快照进行追帧。
- 快速追帧:渲染帧关闭,每帧跑多帧逻辑,追上游戏进程
- 服务端快照:一段时间,存个整个世界的快照,存到硬盘里,断线重连的时候,服务器下发最近的快照,客户端从这个快照进行追帧。
有个问题,顶号的话,客户端快照是不是就失效了?
有了上面的快照技术,就能实现断线重连、观战、回放系统,用的都是一套机制
作弊问题
- 多玩家情况:checkSum技术校验,算出的值不同的玩家就是作弊,踢掉
- 2个玩家情况:这种情况,在服务器没有做校验的情况下,找不出谁开挂,但是只影响一个玩家,影响不大(别跟他玩)
- 全图视野挂很难防:因为每个客户端都有全逻辑,全模拟


状态同步
- 以服务器为权威
- 从客户端接受输入和状态,在服务端模拟整个完整世界
- 下发各个客户端需要的逻辑
- 有一定的防作弊能力

- Authorized(1P):玩家本地端
- Replicated(3P):在其他玩家端的复制品
- Server:权威服务器
Dumb Client Problem
客户端在没收到状态同步的时候,不能做任何操作。
就显得很呆,怎么解决这个问题呢?
客户端预测
服务端矫正 客户端预测
客户端总是比服务端提前预测半个RTT+一个命令帧的时间(守望先锋策略)

服务端矫正
- Buffer
- 把每次预测的状态存下来,服务端下发状态的时候,跟半个RTT前存的状态比对,如果一样,预测就是正确的
- Ring buffer for states
- Ring buffer for inputs
- 如果预测错误,客户端需要接受服务端的状态,全部重新计算

丢包处理
丢包,服务器直接复制你最后的操作进行操作,比如你断线,让你一直往前跑 |
|