当前位置: 首页 > news >正文

11. 网络同步模型 - 状态同步A

1.状态同步简介

2.状态同步的优缺点

3.客户端给服务器发送什么/服务器给客户端返回什么


1.状态同步简介

状态同步是一种网络同步模型, 服务器是唯一的世界权威, 它负责计算所有的游戏逻辑和确定性的状态结果, 然后讲这个状态快照广播给所有客户端, 客户端根据这个快照来更新和渲染自己的游戏世界一个简单的比喻:一群学生在看老师讲课, 老师(服务器)手里有唯一正确的答案(游戏状态); 老师会定期地把答案写在黑板上(发送状态快照),学生们(客户端)根据黑板上的答案来修改自己作业本上的内容(更新本地状态); 学生们不需要知道计算过程, 只需要相信并显示最终答案即可

2.状态同步的优缺点

1).状态同步的优点a.权威性 - 最核心的优点- 是什么? 服务器是唯一的上帝, 是所有游戏状态的唯一真相来源; 客户端只是一个观众, 负责展示从服务器收到的状态- 为什么好?反作弊能力强, 所有关键逻辑(比如: 这一枪打没打中, 这个技能造成多少伤害)都在服务器上计算和验证, 客户端只是发送"我想移动""我开枪了"的请求; 比如一个作弊玩家试图修改本地内存, 把自己的速度调得飞快或让自己穿墙他发给服务器的请求会被服务器基于权威状态进行校验, 然后直接拒绝; 他只能自嗨, 影响不了其他玩家- 比喻无论你本地怎么乱拼乐高, 最终都必须以我发的"全景照片"为准; 你说你拼了个火箭, 我照片里没看到那就是没有b.开发简单 - 逻辑清晰, 易于实现- 是什么?游戏的核心逻辑几乎只在服务器编写与维护- 为什么好?避免歧义, 不会出现"在我的屏幕上打中了, 在他的屏幕上却打空了"这种逻辑冲突, 一切以服务器判定为准天然支持断线重连, 玩家掉线后重连, 服务器只需要把当前完整的游戏状态"全景照片"发给他一份, 他立刻就能同步到最新进度, 非常简单直接c.抗丢包能力强- 是什么?即使网络发生丢包, 游戏体验也不会雪崩- 为什么好?状态同步发送的是状态快照, 如果中间丢了一个包, 没关系, 下一个包就会带来更新的状态; 客户端可以平滑地插值到最新状态, 玩家可能只会感觉到一点点跳跃或卡顿, 但游戏很快能恢复正常d.异构性支持 - 欢迎围观群众- 是什么?可以轻松支持不同步调的玩家- 为什么好?新玩家可以随时加入游戏, 服务器给他发一份当前状态即可; 观战者, 直播流也可以轻松实现; 因为服务器只需要把状态数据也发给观战客户端就行e.动态负载均衡 - 是什么?可以将不同区域的玩家分配到不同的服务器进程上处理 - 为什么好?大世界游戏中, 服务器可以把远距离的玩家分到不同的服务器上去, 只在必要时交换数据, 从而支持更庞大的世界和更多的玩家

2).状态同步的缺点a.带宽消耗巨大- 为什么?因为每次同步的是状态结果(坐标, 旋转, 血量等), 而不是操作指令(按键W, 点击鼠标等); 状态数据的数据量远大于制作指令; 并且为了保持世界的实时性, 必须以很高的频率(每秒10 - 30)向所有相关客户端广播这些数据;玩家越多, 需要同步的实体就越多, 带宽压力呈指数级增长- 带来什么影响?服务器成本高昂, 服务器出口带宽是游戏运营的主要成本之一; 状态同步意味着需要支付昂贵的带宽费用玩家网络要求高, 玩家需要稳定且带宽足够的网络来接收海量数据, 网络环境较差时, 容易因数据拥堵而导致卡顿b.延迟感和响应性- 为什么?所有逻辑计算都在服务器端完成, 你的任何一个操作(如移动, 开枪)都需要发送到服务器, 服务器计算处理并进行校验服务器将结果广播回来, 这样客户端才能看到结果; 这一个来回(RTT)就产生了延迟- 带来什么影响?操作感不跟手, 尤其是延迟较高的情况下, 玩家会感觉自己的操作有粘滞感, 响应不够及时; 需要预测和插值, 为了弥补这个缺点, 客户端必须引入复杂的预测算法(服务器确认前先本地移动)和插值算法(平滑处理其他实体移动), 但这又会带来新的问题(预测错误时的回拉)c.同步规模受限- 为什么?服务器的带宽和算力是有极限的, 它无法无限制地同时向成千上万个客户端广播成千上万个实体的全量状态数据- 带来什么影响?必须引入兴趣范围, 为了解决这个问题, 开发者必须引入兴趣范围机制; 服务器只同步玩家周围一定范围内的实体状态; 限制游戏设计, 直接限制了超大规模同屏战斗的实现, 无法做出万人同屏且每个人都能精细交换的战斗, 因为带宽无法承受

状态同步中用于同步状态的数据包较大, 因此带宽消耗就越大; 可以将带宽看作一条公路, 数据就像公路上跑的车; 车越多,越大, 需要的公路就越宽, 否则堵车; 详细分析一下为何数据越大, 越多, 消耗的带宽就越大1).数据的物理体积就变大了每个你在游戏里同步的信息, 无论是位置, 旋转, 血量还是一个技能状态在网络上传输时, 最终都会被转换成由01组成的二进制数据a.一个数字, 比如一个玩家的x坐标, 假设用一个float(单精度浮点数)来存储, 它需要4个字节b.更多数字, 如果你要同步一个完整的位置(x, y, z)那就是3float, 它需要12个字节c.更多玩家, 这还是只是一个玩家的数据; 如果一场游戏中有10个玩家, 服务器每秒都要给所有客户端发送10次这样的数据; 光是这部分数据量已经很大了注: 同步的状态信息越详细, 数据的体积就自然越大, 每次发送需要的空间就越多 2).数据包的额外开销就增加了网络数据并不是只传输你的游戏数据本身, 每个数据包都像一封信, 里面除了信纸(你的游戏数据), 还有信封和邮票a.协议头每个基于TCP的数据包, 都自带了IP头, TCP头信息, 这些头信息包含了目标地址, 端口, 序列号等确保数据能够正确送达的信息; 这部分开销通常是20 - 60个字节左右b.关键点这个信封的大小是固定的, 如果你只发送4个字节的玩家流量, 那么总数据包大小可能是20() + 4(数据) = 24字节, 有效数据的占比非常低, 大部分带宽都被信封消耗了c.优化策略正因为有这种开销, 游戏网络编程中才要采样"快照"机制; 即把多个实体(玩家, 怪物, 子弹)的状态打包在一个大数据包里发送; 这样多个数据共享一个协议头, 大大减少了信封带来的浪费但是, 即使采用了快照优化, 快照里包含的实体越多, 每个实体的状态数据越丰富, 这个总数据包的大小依然会线性增长,消耗的带宽也就越大3).更新频率的乘法效应状态同步不是一次性发送完就结束的, 它需要高频率地, 持续地发送a.每秒发送20次 vs 每秒发送5, 假设一个玩家的状态数据是50字节- 如果服务器每秒发送5, 那么每秒消耗的带宽大约是50字节 * 5 = 250字节/- 如果为了更平滑的同步, 每秒发送20, 那么带宽消耗就变成50字节 * 20 = 1000字节/; 频率提供4, 带宽消耗也提供四倍b.玩家数量的乘法, 再考虑玩家数量的因素; 10个玩家, 每个玩家50字节, 每秒20, 那么服务器发出的总数据量就是50 * 10 * 20 = 10000字节/秒 数据量(实体的大小) * 实体数量 * 更新频率这三个因素共同决定了总带宽消耗, 任何一个数值增加, 都会直接导致总宽度需求上升       

3.客户端给服务器发送什么/服务器给客户端返回什么

1).客户端给服务器发送"操作指令"客户端不会把自己的坐标, 血量等状态发给服务器, 否则就失去了服务器权威的意义了; 它发送的是玩家的输入信息比如: 键盘按键(W/A/S/D), 鼠标移动和点击, 技能释放等; 对于按下摇杆这个操作, 应保持低频向服务器发送消息2).服务器给客户端返回"权威状态快照"服务器收到所有客户端的输入后, 在自己的游戏逻辑中处理这些输入, 计算出下一时刻整个游戏世界的完整状态, 然后打包发送给客户端a.内容: 所有相关游戏对象的最新, 最正确的状态数据, 例如: 玩家A的坐标(x, y, z), 旋转, 血量值等b.频率: 低于客户端发送操作的频率(例如每秒10 - 20), 以节省带宽   

分析客户端处理摇杆向服务器发送1).摇杆状态的变化a.摇杆从松开到按下: 开始移动, 这是一个重要事件, 需要立即通知服务器b.摇杆从按下到松开: 停止移动, 同样需要立即通知服务器c.移动方向发生重大改变: 比如从向前突然变为向后, 也应该立即发送2).以一个固定的、较低的频率向服务器发送这一步是为了告诉服务器"我还在按着", 从服务器的角度看问题a.时刻T0: 我收到客户端A发来的一个包, 内容是{ "move": true, "dir": {0, 1} }服务器的理解: 用户A想开始向前移动, 然后会根据他的速度和方向持续更新他的位置b.时刻T1(100ms), 没有收到任何新包来自客户端A- 服务器的思考: 用户还是在移动吗, 有没有可能他其实在50ms的时候就松开了摇杆, 但那个包因为丢包还没有掉, 服务器无法确定真相- 服务器的决策: 为了保险起见, 为了避免出现"玩家明明松手了角色还在跑"的严重不同步, 服务器最合理的做法就是假定他已经停止了输入, 让他的角色停止移动c.结果- 在客户端A的屏幕上, 因为他本地一直在预测, 他看到自己还在跑- 在服务器和其他玩家的屏幕上, 客户端A的角色在跑了一小段之后突然停止了- 当客户端A终于发送下一个包时, 会发送一次剧烈的回滚校正, 客户端A的角色被拉回到服务器早已停止的位置, 玩家会看到自己的角色闪现了一下解决方案: 客户端需要通过这个低频的包(每秒多少次), 来让服务器确认玩家当前的"操作意图"仍然有效

状态同步中服务器为什么要以固定的频率给客户端进行广播?1).控制带宽, 避免网络洪水这是最直接, 最现实的原因, 网络带宽是极其宝贵且有限的资源a.想象一下: 一个游戏中有100个玩家, 每个玩家的位置, 速度, 动作, 血量等状态每时每刻都在发生极其微小的变化;如果服务器在每一次微小的变化后都立刻向所有客户端发送一个更新包, 网络会瞬间被海量的数据包淹没, 导致严重的拥堵和丢包, 游戏根本无法进行b.解决方案: 采用固定频率广播, 服务器就像一个节拍器, 每隔一个固定的时间间隔(如50ms), 它就把当前这一刻所有玩家的完整状态快照收集起来, 打成一个数据包, 再广播出去; 这就像把很多小货物攒成一个集装箱再发货, 远比零散发送无数个小包裹要高效得多, 极大节省了带宽比喻: 这就像看电视新闻, 电视台不会每发生一件小事就立刻插播, 而是把一段时间内发生的新闻收集起来, 在固定的整点或半点集中播报; 这样效率最高, 观众也能获得一段时间内完整的信息2).为服务器和客户端减负a.对服务器, 服务器的任务是模拟整个游戏世界, 处理所有玩家的输入, 进行物理计算和碰撞检测等; 如果它每计算出一个变化就立刻准备和发生网络数据, 它的CPU会疲于应付网络I/O(输入/输出), 而没有足够的时间进行核心的游戏逻辑计算; 固定频率让服务器可以安心计算一段时间, 然后在最后一个时间点集中处理网络发送, 工作流程变得井井有条b.对客户端, 客户端同样需要接收, 解析网络数据包, 并更新游戏状态; 固定频率的更新让客户端知道我大概在什么时候会收到下一个更新, 从而合理分配资源进行渲染和预测3).保证公平性固定频率的更新为所有玩家提供了一个相对公平的竞争环境, 所有客户端都在大致相同的时间间隔接收来自服务器的权威信息, 没有哪个玩家会因为某种原因而更频繁的状态信息, 这维护了游戏的一致性基础4).为了应对网络波动网络环境是不可靠的, 数据包可能会丢失, 延迟或乱序到达a.每个包都是重要的: 由于每个状态同步包都包含了一个完整的快照, 即使客户端丢失了一个包, 它也只需要等待下一个固定频率到来的包就可以迅速更新到最新状态, 而不会造成灾难性的不同步b.如果实时发送, 丢失任何一个代表微小变化的包, 都可能意味着客户端永远丢失了这个变化, 导致与服务器的状态出现永久性的偏差, 最终只能通过强制重置等粗暴方式来同步

文章转载自:

http://Yu0w7HV2.trqzk.cn
http://25CB0UDe.trqzk.cn
http://4AC31TfT.trqzk.cn
http://OYQSzCIE.trqzk.cn
http://RrewDcni.trqzk.cn
http://vb1nNZX1.trqzk.cn
http://qnJygB0w.trqzk.cn
http://XxkVYMN1.trqzk.cn
http://MgnncK7t.trqzk.cn
http://KJIPhLse.trqzk.cn
http://Lk42KJlM.trqzk.cn
http://J04F9RuA.trqzk.cn
http://gNU7Wk3B.trqzk.cn
http://7ctQ1bo4.trqzk.cn
http://O4xGWWpj.trqzk.cn
http://AeMNUW8F.trqzk.cn
http://ZnchkDVk.trqzk.cn
http://VmAaOSc1.trqzk.cn
http://xboOmB06.trqzk.cn
http://YWG42o2G.trqzk.cn
http://IOLb5xJU.trqzk.cn
http://gii2GHMI.trqzk.cn
http://P0AyyuCk.trqzk.cn
http://voU80ddB.trqzk.cn
http://nhWBR9Iw.trqzk.cn
http://TKQvob3w.trqzk.cn
http://1UKy2Mkv.trqzk.cn
http://RiDj0IIM.trqzk.cn
http://IicoN6aH.trqzk.cn
http://6IdTkQQt.trqzk.cn
http://www.dtcms.com/a/380912.html

相关文章:

  • Mem0 + Milvus:为人工智能构建持久化长时记忆
  • 力学矢量三角形“无脑”求解指南:基于极角代数的系统化方法
  • 算法第四题移动零(双指针或简便设计),链路聚合(两个交换机配置)以及常用命令
  • 背包问题从入门到入土
  • 远程连接--向日葵
  • 植物灯电源芯片选型指南:如何实现高效与智能?
  • Python读取视频-硬解和软解
  • FFmpeg vs 去水印软件:哪种方式更适合你?
  • Java垃圾回收机制理论算法及使用
  • 【Vue2 ✨】Vue2 入门之旅 · 进阶篇(六):keep-alive 与缓存机制
  • IDA pro 生成idapro.hexlic
  • 【CE】CE教程Tutorial:进阶篇(第8关:多级指针)(Pointer Scan工具)
  • Java 更改 Word 文档中文本颜色
  • Cesium 无人机航线规划(环点航线)
  • 一般软件加载显示图片的流程
  • 第十四届蓝桥杯青少组C++选拔赛[2023.1.15]第二部分编程题(3、寻找花坛)
  • Spring Boot中Filter与Interceptor的区别
  • 生产常见问题
  • Linux copy_from_user
  • 数据库:mysqld服务器启动参数大全
  • STM32之RTC
  • 正式工作一年半了 小记一下
  • HDFS与Yarn深入剖析
  • 空间信息与数字技术和传统GIS专业有何不同?
  • 企业内训|智能驾驶案例及实践——某央企汽车集团
  • 告别繁琐配置!Retrofit-Spring-Boot-Starter让HTTP调用更优雅
  • 星座SAR动目标检测(GMTI)
  • Python异常处理自定义:从基础到高级的完整指南
  • R语言水文、水环境模型优化:从最速上升法、岭分析到贝叶斯优化与异方差处理,涵盖采样设计、代理模型与快速率定等
  • PHP启动报错:liboing.so.5:cannot op如何处理?