UDP帧同步核心原理
2023-06-13 09:14:11 时间
- 本博客总结自网络公开课
- 开发工具:Unity/服务器
- 开发语言C#/(C++ Lua)
目录
帧同步如何同步
- 帧同步:服务器把玩家操作同步给所有玩家,其他玩家在本地客户端根据服务器发过来的操作来推进游戏。同样代码+同样输入->同样结果
- 优点:实时性很好 缺点:所有计算放在客户端,容易作弊(即逻辑和单机游戏没有区别),每次同时同步的玩家不能太多
- 原理: 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的时序和丢包问题
- 客户端:丢包,服务器会补发丢掉和没有到的帧。
- 服务器:丢包(某一帧)无严重影响
相关文章
- 并发与并行,同步和异步,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang并发编程之GoroutineEP13
- 大型第三方源代码的同步
- Golang 并发&同步的详细原理和使用技巧
- 深入浅出阿里数据同步神器:Canal原理+配置+实战全网最全解析!
- 【OkHttp】OkHttp 源码分析 ( 同步 / 异步 Request 请求执行原理分析 )
- 一文详解MySQL主从同步原理
- mysql主从同步原理及应用场景示例详解
- python代码定时同步本机的北京时间详解编程语言
- Ajax 同步异步互相转换以及区别详解编程语言
- MySQL主从复制监控:保障秒级数据同步(mysql主从复制监控)
- MySQL 数据同步原理及实施方法(mysql同步原理)
- 深入理解Redis主从同步原理(redis主从同步原理)
- linux线程同步实现原理分析(linux线程同步)
- MySQL实时同步:实现原理及其应用(mysql实时同步原理)
- Linux时间同步服务器:确保时间准确。(linux时间同步服务器)
- Linux下NTP时钟同步: 精确、可靠的时间同步服务(linux下ntp)
- Linux 同步命令:简单而强大(linux同步命令)
- 解读Oracle数据库的高效数据同步方案(oracle数据同步方案)
- 探究 Linux 中的同步异步原理(linux同步和异步)
- Oracle数据库全量同步的实现原理(oracle全量同步原理)
- DSP大规模数据同步至Oracle数据库(dsp发送oracle)
- MySQL高可用架构实现三主三从同步备份技术(mysql三主三从)
- Oracle主从模式实现数据同步的原理(oracle主从模式原理)
- 千万级大数据同步之Redis智能引擎(千万数据redis同步)
- Redis集群同步揭秘背后的原理(redis集群同步原理)
- cwrsync实现从linux到windows的数据同步备份
- 多ajax请求的各类解决方案(同步,队列,cancel请求)
- MYSQL主从不同步延迟原理分析及解决方案
- C#委托的三种调用示例(同步调用异步调用异步回调)