游戏通讯技术:帧同步技术

现代多人游戏中,多个客户端之间的通讯大多以同步多方状态为主要目标,为了实现这一目标,主要有两个技术方向:

  • 状态同步
  • 帧同步

1. 状态同步

状态同步简单来说就是同步游戏中的各种状态,当客户端发送游戏动作到服务器,服务器接收到之后,通过计算游戏行为的结果,然后广播下发给客户端游戏中的各种状态数据。客户端接收到状态数据后显示内容。这种做法类似于各个客户端都在远程操作服务器上的软件。例如最高的mud,以及日后大量的国产网游,特别是回合制游戏,大多采用这种方式。

状态同步的流程:

  1. 客户端上传操作到服务器
  2. 服务器收到后计算游戏行为的结果(如技能逻辑、战斗计算等)
  3. 服务器以广播的方式下发游戏中各种状态
  4. 客户端收到状态后更新本地状态(如动作状态、Buff状态、位置等)

为了给游戏玩家更好的体验,减少同步的数据量,客户端也会做很多的本地运算,减少服务器同步的频率以及数据量。

状态同步其实是一种不严谨的同步,它的思想中不同玩家屏幕上的一致性的表现并不是重要指标,只要每次操作的结果相同即可。所以状态同步对网络延迟的要求并不高。例如:RPG游戏中200~300ms的延迟对用户来说是可以接受的,但在RTS(即时战略)游戏中50ms的延迟却会很受伤。

2. 帧同步

    帧同步是RTS(即时战略)游戏经常采用的一种同步技术,状态同步中数据量会随着需要同步的单位数量增长,而对于RTS来讲动不动就是几百个单位可以被操作,如果这些都需要同步的话,数据量是不能被接受的,所以帧同步不同步状态,只同步操作。例如:游戏中同步玩家的操作指令,操作指令包含当前的帧索引

    简单来说,客户端发送游戏动作到服务器,服务器接收并汇总,然后直接转发给所有客户端,或者客户端直接通过 P2P 技术发送。
    客户端根据收到的游戏动作来做运算和显示。这种做法等于客户端之间相互远程控制其他客户端上的游戏软件。早期的 ipx 网络游戏,例如红色警戒、帝国时代、星际争霸,以及大量支持网络连线双打游戏机模拟机,都是采用这种方式。

那些游戏需要使用帧同步呢?

  • 多人实时对战游戏
  • 游戏中需要战斗回放功能
  • 游戏中需要加速功能
  • 需要服务器同步逻辑校验防止作弊

帧同步的流程

  1. 同步随机种子:游戏中设计随机数的使用,通过同步随机数种子可以保持随机数的一致性。
  2. 客户端上传操作指令给服务器,操作指令包含游戏操作当前帧索引
  3. 游戏广播所有客户端的操作,如果没有操作也要广播空指令来驱动游戏帧前进。

帧同步

    帧同步主要依赖客户端的能力,服务器仅仅是做一个转发,甚至客户端可以无需服务器,通过 P2P 方式来转发数据。由于只是转发游戏的行为,所以广播的数据量比状态同步要小很多。非常适合游戏行为非常频繁的动作游戏,诸如飞行射击、FPS、RTS(即时战略)。

状态同步
    状态同步由于要把整个游戏的状态都广播下去,如果游戏中的对象特别多,比如满屏的子弹、怪物,那么要广播的数据量就会很大,这个时候帧同步的优势就比较明显,因为不管有多少”机器控制的角色“,仅仅需要广播玩家角色有关的操作即可。
    反过来,如果游戏中有大量玩家同时聚集,那么帧同步状态同步的差异就不太明显。反而状态同步能得到更多安全性,因为游戏运算在服务器上,比较容易防止外挂。

    简单来说,帧同步技术最要的概念是”相同的输入 + 相同的时机 = 相同的显示“。也就是说,游戏接收来自网络的多个客户端的操作,如果这些操作在各个客户端上都是一样的,那么多个客户端的显示也就是一样的,进而带来了”同步“的效果。
    在这种情况下,各个客户端的运算要绝对一致,不能依赖诸如本地时间、本地随机等”输入“,而要一切以网络来的数据为主。

帧同步

   因为帧同步的特性,因此很容易做出战斗回放,即服务器记录所有操作,客户端请求到操作文件再执行一次。帧同步的特性导致客户端的逻辑实现和表现实现必须完全分离。

    帧同步的目的在于消除网络波动性带给玩家的卡顿以及忽快忽慢的不良体验。

网络波动的平滑处理

3. 状态同步和帧同步的比较和选择

    对于单位比较多的即时策略游戏,帧同步是很好的选择。相反的,如果玩家比较多,状态同步则更加合适,因为安全性更高。一般大型MMOARPG(大型多人在线角色扮演类游戏)都采用状态同步,由于状态同步采用C/S架构,所有状态由服务器来控制,安全性比较高,但流量比较大。帧同步采用的是囚徒模式,所有C端强制采用一个逻辑帧率,从而保证输出一致,其特点是流量小,安全性较差。

    囚徒模式又叫锁步模式,就是把所有参与对战的客户端看成排成一列的囚犯,这些囚犯们的左脚都被锁链给连起来,如果要往前走,就只能同时迈步,如果其中某个人走快了或走慢了,都回让整队人停下来。

状态同步和帧同步的比较

3. 帧同步的基本原理

    帧同步是一种对同步源进行像素级同步显示的处理技术,对于网络上的多个接入者,一个信号将会通过主机同步发送给其他人,并同步显示在各个终端上。同步信号可以是每帧的像素数据,也可以是影响数据变化的关键事件信息。

    帧同步在网络游戏应用中的设计有别于传统的MMORPG游戏,因为可以承载大量的后台计算,实现类单机的效果,所以可以在射击类、飞行类游戏中实现弹幕计算或格斗类的高精度打击效果。

    什么叫做帧同步呢?服务器收集客户端手机发送过来的操作,然后在特定的时间(收集完成之后),再广播发送给每个客户端。客户端根据接收到的输入,进行同样的逻辑处理,最终得到同样的结果的过程。在实现上,一般都是以服务器按固定的帧率,来搜集每个客户端的输入,然后把这些输入广播给所有客户端。由于每个操作指令到达所有客户端的时间(帧)都是一样的,所以每个客户端运算的结果也是一样的,也就是同样的输入就会得到同样的结果。

这就好像是玩家通过网络将操作手柄连接到你的手机,这种同步方案是传统单机局域网游戏中最常见的。

帧同步

    帧同步模型最大的优点在于强一致性,每个客户端的表现是完全一样的,非常适合高度要求操作技巧的游戏。由于广播的仅仅是玩家的操作,所以数据量很少。不管游戏中的角色数量、状态数量有多大多复杂,都不会影响广播的数据量。

    帧同步模型最大的缺点是对所有玩家的延迟都有要求,一般来说要求在50毫秒以内,如果有一个客户端网络卡住了,所有客户端都要停下来等待。

    另外在帧同步模式中,数据同步的频率较高,网络延迟越小越好。由于TCP的滑动窗口机制和重传机制,导致延时机制,导致延时无法控制。因此帧同步一般采用UDP进行网络传输,但UDP又会衍生出可靠性问题,对于客户端,如果某些UDP包没有收到,就会出现丢帧的情况。

    帧同步技术原理

    客户端A的操作A1与客户端B的操作B1,共同封装成OperateCmd数据发送给PVP服务器,PVP服务器每66毫秒产生一个逻辑祯,在该桢所在时间段内,收到A1和B1后,生成一个Frame数据块,在该帧时间结束时,将Frame发送给客户端A和B。Frame数据块内有该帧的帧号,客户端A和B接收到Frame数据后,便知道该帧内,客户端A和客户端B都做了什么操作。然后根据接收到的消息A1和B1进行游戏表现,最终呈现给玩家A和B的结果是一致性的,从而实现客户端A和B的数据同步。

帧同步

    帧同步既然是在特定时间发送,也就是说每隔一段时间收集用户操作指令,那么要间隔多久内。例如每隔一段时间搜索用户的操作。此时,如果时间太快则网络速率达不到要求,如果时间太长则用户操作不流程。哪里多少才比较合适呢?根据统计玩家至少要在50ms 100ms可以完成一次,一般维持到1520次左右会比较安全。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
上传限制,共分四卷压缩。请务必下载完所有压缩包。 目录 第一篇 软件设计基础篇 第1章 软件开发起步 2 1.1 建立MFC应用程序 2 1.2 分析框架结构 4 1.2.1 框架代码文件的结构 4 1.2.2 应用程序类 5 1.2.3 对话框类 6 1.2.4 添加消息响应 7 第2章 对话框应用程序 9 2.1 模态对话框 9 2.1.1 实例:使用MFC实现模态对话框 9 2.1.2 实例:使用Win32 API实现模态对话框 10 2.2 非模态对话框 12 2.2.1 实例:使用MFC实现非模态对话框 12 2.2.2 实例:使用Win32 API实现非模态对话框 13 2.3 属性对话框 14 2.3.1 实例:多页面切换程序 14 2.3.2 实例:向导对话框 16 2.4 对话框设计技巧 17 2.4.1 控件对齐与排列 17 2.4.2 设置控件逻辑顺序 18 2.5 通用对话框 19 2.5.1 实例:通用“打开”和“另存为”对话框 19 2.5.2 实例:通用“字体”对话框 22 2.5.3 实例:通用“颜色”对话框 23 第3章 基本控件 26 3.1 按钮控件 26 3.1.1 按钮CButton类 26 3.1.2 实例:按钮控件的使用方法 28 3.2 编辑框 30 3.2.1 编辑框CEdit类 30 3.2.2 实例:编辑框的使用方法 32 3.3 列表框 33 3.3.1 列表框CListBox类 33 3.3.2 实例:列表框的使用方法 35 3.4 组合框 36 3.4.1 组合框CComboxBox类 37 3.4.2 实例:组合框的使用方法 39 3.5 进度条 41 3.5.1 进度条CProgressCtrl类 41 3.5.2 实例:进度条的使用方法 42 3.6 列表控件 44 3.6.1 列表控件CListCtrl类 44 3.6.2 实例:列表控件的使用方法 45 第4章 文档与视图 47 4.1 文档—视图结构 47 4.1.1 单文档与多文档 47 4.1.2 文档与视图体系 48 4.2 实例:单文档应用程序与文档串行化 52 第5章 GDI绘图技术 57 5.1 图形设备接口GDI 57 5.1.1 设备上下文 57 5.1.2 GDI对象 58 5.1.3 GDI绘图 58 5.2 画笔 58 5.2.1 画笔CPen类 58 5.2.2 实例:使用GDI对象CPen绘图示例 59 5.3 画刷 60 5.3.1 画刷CBrush类 60 5.3.2 实例:使用GDI对象CBrush绘图示例 61 5.4 位图 63 5.4.1 位图CBitmap 63 5.4.2 实例:使用GDI对象CBitmap示例 64 第6章 键盘与鼠标消息 67 6.1 键盘消息 67 6.1.1 键盘消息的类型 67 6.1.2 实例:响应键盘消息示例 68 6.1.3 模拟键盘消息 70 6.1.4 实例:模拟键盘消息示例 71 6.2 鼠标消息 72 6.2.1 鼠标消息的类型 72 6.2.2 实例:处理鼠标消息 73 6.2.3 实例:模拟鼠标消息 74 第二篇 软件设计综合应用篇 第7章 网络通信基础 80 7.1 网络模型 80 7.1.1 OSI参考模型 80 7.1.2 TCP/IP参考模型 81 7.2 基础协议 82 7.2.1 IP协议 82 7.2.2 TCP协议 83 7.2.3 UDP协议 84 7.2.4 ICMP协议 85 7.3 套接字编程 85 7.3.1 函数介绍 85 7.3.2 实例:Ping程序 88 7.3.3 实例:网络嗅探器 92 7.4 服务器与客户端模型 96 7.4.1 实例:TCP服务端和客户端程序 96 7.4.2 实例:UDP服务器和客户端程序 100 7.5 实例:使用分层服务提供者LSP截取网络数据包 103 7.5.1 服务提供者接口(SPI) 103 7.5.2 设计实例 103 7.5.3 枚举协议目录 106 7.5.4 LSP的安装与卸载 108 7.5.5 分层服务提供者(LSP) 113 第8章 密码学算法 118 8.1 数据加密标准(DES) 118 8.1.1 算法描述 118 8.1.2 初始置换与逆初始置换 119 8.1.3 生成子密钥 120 8.1.4 f函数的执行流程 121 8.1.5 解密过程 122 8.1.6 实例:DES算法加密解密演示 123 8.2 国际数据加密算法(IDEA) 131 8.2.1 算法描述 131 8.2.2 生成子密钥 133 8.2.3 实例:IDEA算法加密解密演示 134 8.3 Blowfish算法 139 8.3.1 算法描述 139 8.3.2 生成子密钥和S盒 141 8.3.3 实例:Blowfish算法加密解密演示 141 8.4 公钥加密算法(RSA) 146 8.4.1 算法描述 146 8.4.2 实例:RSA加密解密演示软件 147 第9章 多媒体技术 151 9.1 多媒体控件 151 9.1.1 实例:使用Animation控件播放AVI文件 151 9.1.2 实例:使用Windows Media Player控件播放多媒体文件 152 9.1.3 实例:使用Real Player控件播放多媒体文件 153 9.2 屏幕截图 154 9.2.1 位图 154 9.2.2 实例:屏幕截图 155 9.3 屏幕录像 157 9.3.1 实现原理 157 9.3.2 实例:屏幕录像 158 第10章 数据库技术 161 10.1 设置ODBC数据源 161 10.1.1 ODBC数据源 161 10.1.2 使用ODBC管理器设置Access数据源 162 10.2 MFC ODBC数据库编程 163 10.2.1 MFC ODBC概述 163 10.2.2 实例:使用MFC ODBC访问数据库 164 10.3 MFC DAO数据库编程 169 10.3.1 MFC DAO概述 169 10.3.2 实例:使用MFC DAO访问 数据库 169 第11章 综合实例开发 174 11.1 实例:Huffman编码软件 174 11.1.1 Huffman算法原理 174 11.1.2 具体实现 175 11.2 实例:八数码游戏 178 11.2.1 八数码游戏算法介绍 178 11.2.2 具体实现 179 11.3 实例:游戏寻路算法A* 183 11.3.1 A*算法原理 183 11.3.2 二叉堆在A*中的应用 184 11.3.3 具体实现 186 11.4 实例:“连连看”游戏辅助工具 190 11.4.1 “连连看”算法原理 190 11.4.2 具体实现 191 11.5 实例:“对对碰”游戏辅助工具 196 11.5.1 “对对碰”算法原理 196 11.5.2 具体实现 197 11.6 实例:拼音输入法 199 11.6.1 设计实例 200 11.6.2 拼音字典存储结构—Trie树 200 11.6.3 单字联想 205 11.7 实例:Windows二级文件系统 209 11.7.1 设计实例 209 11.7.2 具体实现 211 11.8 实例:手柄测试器 214 11.8.1 DirectInput手柄输入 214 11.8.2 设计实例 216 第三篇 Windows系统程序设计篇 第12章 进程与线程 222 12.1 进程 222 12.1.1 原理介绍 223 12.1.2 创建进程 223 12.1.3 实例:创建进程 226 12.2 线程 227 12.2.1 原理介绍 227 12.2.2 创建线程 229 12.2.3 实例:创建线程 229 12.3 枚举进程/线程信息 231 12.3.1 实例:使用PSAPI示例 231 12.3.2 实例:使用ToolHelpAPI示例 233 12.3.3 实例:使用Native API示例 235 第13章 内存管理 239 13.1 虚拟内存 239 13.1.1 进程虚拟地址空间 239 13.1.2 实例:查看虚拟内存状态 240 131.3 实例:演示虚拟内存的“保留—提交”特性 243 13.1.4 实例:游戏内存修改器 245 13.2 内存映射文件 249 13.2.1 内存映射文件的原理 249 13.2.2 实例:文件分割器 250 第14章 进程间通信 254 14.1 消息传递机制 254 14.1.1 消息传递 254 14.1.2 实例:使用WM_COPYDATA消息传递数据 254 14.2 共享内存 256 14.2.1 共享内存的原理 256 14.2.2 实例:使用共享内存示例 257 14.3 管道和邮槽 259 14.3.1 管道和邮槽通信原理 259 14.3.2 实例:使用匿名管道重定向程序输出 261 14.3.3 实例:命名管道示例 263 14.3.4 实例:邮槽通信示例 266 14.4 剪贴板 267 14.4.1 剪贴板通信机制 267 14.4.2 实例:使用剪贴板实现进程间通信示例 269 第15章 线程同步 275 15.1 原子访问 275 15.1.1 多线程访问共享数据问题 275 15.1.2 互锁系列函数 276 15.2 关键代码段 277 15.2.1 基本原理 277 15.2.2 实例:多线程环境下的数据共享 278 15.3 内核对象与等待函数 280 15.3.1 内核对象 280 15.3.2 等待函数 281 15.4 事件内核对象 283 15.4.1 基本原理 283 15.4.2 实例:使用事件内核对象示例 284 15.5 等待定时器内核对象 285 15.5.1 基本原理 285 15.5.2 实例:使用等待定时器的APC机制 287 15.6 信标内核对象 288 15.6.1 基本原理 288 15.6.2 实例:使用信标内核对象示例 289 15.7 互斥内核对象 291 15.7.1 基本原理 292 15.7.2 实例:使用互斥内核对象示例 292 第16章 动态链接库 295 16.1 DLL基础 295 16.1.1 DLL的隐式链接 295 16.1.2 DLL的显示加载 296 16.2 编写动态链接库 297 16.2.1 入口函数DllMain 297 16.2.2 实例:编写DLL实现导出变量、函数、类 298 16.3 线程本地存储器(TLS) 301 16.3.1 静态TLS和动态TLS 301 16.3.2 实例:使用静态TLS示例 303 16.3.3 实例:使用动态TLS示例 304 第17章 结构化异常处理 306 17.1 SEH的概念、特性 306 17.2 SEH的基本使用方法 307 17.2.1 结束异常程序 307 17.2.2 异常处理程序 310 17.2.3 顶层异常处理 313 17.3 VC++编译器级SEH的具体实现 313 17.3.1 SEH相关数据结构的介绍 314 17.3.2 异常处理链结构图 315 17.3.3 实例:单嵌套异常块演示程序 316 17.3.4 实例:多嵌套异常块演示程序 318 17.3.5 VC++编译器级异常帧结构 320 17.3.6 VC中的顶层异常处理 320 17.3.7 VC搜索异常处理程序流程 322 第18章 可执行文件格式 324 18.1 PE文件格式 324 18.1.1 PE文件头 324 18.1.2 可选文件头 325 18.1.3 区块表 327 18.1.4 输入表 328 18.1.5 输出表 329 18.1.6 资源表 330 18.1.7 重定位表 332 18.1.8 绑定输入表 332 18.2 综合应用 333 18.2.1 实例: PE文件资源查看器 333 18.2.2 实例: 为应用程序添加Nag窗口 337 第19章 模块注入与函数挂接技术 341 19.1 模块注入 341 19.1.1 添加导入表项 342 19.1.2 远程线程技术 344 19.1.3 实例:使用远程线程实现模块注入 345 19.1.4 异步过程调用(APC) 346 19.1.5 实例:使用APC实现模块注入 347 19.2 挂接API 349 19.2.1 重定向API 350 19.2.2 实例:重定向API MessageBoxA示例 350 19.2.3 古老的API HOOK 353 19.2.4 实例:HOOK API示例 354 19.2.5 Detours Hook 356 19.2.6 实例:使用detour库实现挂接API示例 357 19.3 钩子 359 19.3.1 钩子的基本原理 359 19.3.2 钩子类型 360 19.3.3 实例:全局鼠标钩子示例 366 19.3.4 实例:全局键盘钩子示例 369 19.3.5 实例:使用局部CBT钩子示例 370 19.3.6 实例:使用低级键盘钩子示例 371 19.4 反注入技术 372 19.4.1 实例:使用调试钩子屏蔽全局钩子 372 19.4.2 实例:检测注入模块 374 19.4.3 实例:使用DLL_THREAD_ATTACH阻止远程线程 377 19.4.4 实例:使用挂钩LoadLibraryExW屏蔽全局钩子 379 附录 光盘源码实例 381

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

查里王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值