UDP帧同步核心原理

2022-10-28 15:04:32 浏览数 (1)

  • 本博客总结自网络公开课
  • 开发工具:Unity/服务器
  • 开发语言C#/(C Lua)

目录

  • 帧同步如何同步
  • 帧同步使用TCP还是UDP
  • 帧同步的流程详解
  • 如何克服UDP的时序和丢包问题

帧同步如何同步

  • 帧同步:服务器把玩家操作同步给所有玩家,其他玩家在本地客户端根据服务器发过来的操作来推进游戏。同样代码 同样输入->同样结果
  • 优点:实时性很好 缺点:所有计算放在客户端,容易作弊(即逻辑和单机游戏没有区别),每次同时同步的玩家不能太多
  • 原理: 1、服务器:每隔一段时间,采集玩家的操作并发送给所有的客户端,并继续采集下一次的操作,等到下一次的发送时间一到,再次发送数据。 2、客户端:收到服务器操作,计算游戏逻辑,上报下一帧操作给服务器
  • 帧同步:服务器每隔多少时间,向客户端发送一次操作比较合适? 上限:网络传送时间 下限:不影响用户体验的情况下的最小数目,人的反应时间一般在50-100ms,即1000ms/50-100->[20,10]即10-20帧为一般的下限。
  • 带宽承受能力如何计算:假设为一个5V5对战游戏 1秒—->平均每帧,每人6个字节,摇杆—>角度(0, 360,2个字节),1个字节(256种不同技能) 16* 10* 15 * 500 = 1,200,000 —> 1.2MBytes;—> 1.2M* 8= 9.6M===>10MBlt带宽;

帧同步使用TCP还是UDP

  • TCP:准确,丢包重传机制 UDP:高效,可能丢包、乱序
  • 通常情况下TCP和UDP都可以使用,但采用UDP主要应对网络波动。 TCP在一个链路传输时,如果遇到网络波动,那么后续帧数据只能等待前面的数据传输完成才能继续传输,会造成延迟。 UDP在传输时会采用不同链路发送,且没有检测机制,因此在某个帧因为网络波动没有传输到的时候,后续帧数据仍可继续进行传输。

帧同步的流程详解

  • 服务器: —>比赛对象—>房间内; (1)服务器上每个比赛对象,都又一个成员frameid,保存了当前比赛,下一帧要进的id; frameid = 1; (2)我们在服务器上定一一个数据结构match_frames,用来保存我们所有的玩家的每帧的操作; match_frames作用:录像回放,断线重连,不同步的情况,有无作弊(调试作用),UDP丢包时序问题要补发给客户端,因此首先要保存起来; (3) next_frame_opt:每帧服务器将采集来的客户端的操作,都存放在这里:frameid = self.frameid, {有操作玩家的操作,有操作玩家的操作,有操作玩家的操作} (4)服务器上启动一个定时器,每隔66MS触发一次on_logic_frame; (5)保存我们当前的操作,到match_frames (6)遍历每个玩家,每个玩家发送我们的帧操作; (7)服务器进入下一帧: self.frameid = self.frameid 1 (8)服务器进入采集下一帧模式,清空上一帧的操作; (9)发送服务器认为这个玩家还没有同步的帧,每个玩家对象,sync_frameid,记录当前这个客户端,已经同步到了多少帧;即从sync_frameid 1开始发送到服务器最新的帧—> UDP丢包和时序问题,补发我们的帧; (10)采用UDP —》将我们100帧的数据包发送出去[100帧:有可能有需要补发的之前的帧数据,此时发送顺序要从那一帧开始[99帧,100帧]]
  • 客户端: (11)客户端,通过网络收到帧同步的数据包以后,调用on_logic_update接收函数 (12)每个客户端,也都会有一个sync_frameid,记录一下当前你这个客户端真正已经同步到哪个帧; (13)如果收到的帧ID,小于客户端已经同步过的帧id,直接丢弃这个帧;因为UDP有后发先到以及先发后到的情况(时序问题),譬如发送的100帧快于99帧先到,此时100帧的数据包中因为服务器记录了sync_frameid,所以一定会补发99-100帧的数据,因此后到的99帧数据就需要舍弃避免重复计算。 (14)如果上一帧的操作不为null,那么这个时候,我们处理下一帧之前一定要先同步上一帧的结果; 确保处理下一帧之前也都是同步的:在播放动画的帧与帧之间,我们会出现时间的差异,会导致位置等不同步;logic_pos: 66ms —>迭代计算出新的位置和结果;同一都以66ms来迭代; 帧同步:每帧都同步,处理下一帧之前,每帧都要同步;—>同样的输入—》同样的输出; (15)跳帧:快速的同步完过时的帧(即直接进行逻辑计算,跳过动画表现等内容),直到最新的帧: 98,帧: [99,100] (16)控制我们的客户端,来根据操作,来播放动画,更新我们的逻辑推进; (17) capture_player_opts:采集自己的操作,上报给服务器,你认为的下一帧(譬如服务器进行到100帧,但客户端仍在上报98帧的内容)next_frame.frameid = this.sync_frameid 1;
  • 服务器接受客户端消息: (18)收到玩家的操作,更新服务器上认为玩家已经处理的帧id; (19)如果收到玩家操作的帧ID,next frame_opts.frameid不等于马上要触发的帧ID;收到玩家过时的炒作; (20)保存玩家的操作,等待一下帧的触发—–> Goto到逻辑4;

如何克服UDP的时序和丢包问题

  • 客户端:丢包,服务器会补发丢掉和没有到的帧。
  • 服务器:丢包(某一帧)无严重影响
udp

0 人点赞