int sock = socket(PF_INET, SOCK_STREAM);
bind(sock, addr);
listen(sock);
allsock.add(sock);
while (1) {
result = select(sock);
if(result > 0) {
int new_sock = accept(sock, &addr);
allsock.add(new_sock);
}
foreach(sock = allsock){
result = select(sock);
if(result > 0) {
char buf[100];
size_t size = read(new_sock, buf, 100);
if(size == 0) {
close(new_sock);
} else {
write(new_sock, buf, size);
}
}
}
}软件性能与开发效率是矛盾的
C/C++ > java > 脚本语言
表 0.1 主要的编程语言与吞吐量
| 语言 | 吞吐量 | 特性 |
|---|---|---|
| C/C++ | 100 | 静态类型, 本地代码 |
| Java/C# | 1 ~ 10 | 静态类型, VM, 字节码 |
| Ruby/Python | 0.1 ~ 1 | 动态类型 |
对于 CPU 密集型应用程序, Java 的运行速度与 C 近似. 但是对于 IO 密集型应用程序, 因为 Java 虚拟机每次进行系统调用, 都会进行缓存溢出检查和异常对象处理, 所以运行速度比 C 慢上 10 倍左右.
动态类型语言则比 Java 更慢, 因为每次进行一些处理时, 对象调用的方法都可能会发生变化, 所以每次调用前都必须进行检查确认.
Go 语言是一种静态的, 本地执行的语言, 它具有垃圾回收机制, 程序员可以在代码的不同部分中选择类型化的强度.
在 Linux 上, 平均每个 CPU 内核一秒内可以执行 10 万~20 万次上下文切换.(这里的上下文切换指的是操作系统调度单元的切换)
libevent 单线程 + 事件驱动 + 非阻塞调用
libevent 最大的特点就是: 它的工作方式并非创建大量线程然会等待 read 等系统调用, 而是"不创建线程, 为每一个想要事先通知的事件注册回调函数, 当事件发生时, 只进行一次函数调用"
DSL(Domain Specific Language 领域特定语言) IDL(Interface Description Language 接口描述语言)
Protocol Buffers Thrift
游戏中的许多物体在同一时刻看上去都在各自运动, 但在系统中并没有用多个线程来并行处理.因此游戏一般是按帧来运算的, 用一个或几个定时循环的线程处理事件来表达场景中的所有物体.
- 开发
- 运维
- 销售
表 2.2 物理结构上的分类及其性质上的差异
| C/S | P2P | |
|---|---|---|
| 延迟(所需时间, 通信延迟) | 大 | 小 |
| 服务器设备成本 | 大 | 小 |
| 带宽成本 | 根据游戏内容决定 | 根据游戏内容决定 |
| 非法行为 | 困难 | 容易 |
MMO Massively Multiplayer Online MO Multi-player Online
表 2.3 逻辑结构上的分类及特征
| MO | MMO | |
|---|---|---|
| 游戏核心 | 少量玩家聚集在一起竞赛 | 大量玩家进行社交活动 |
| 同时玩家数 | 20 左右 | 200~1000000 |
| 延迟 | 50 毫秒 | 300 毫秒 |
| 游戏时间(累积) | 几分钟 | 几年 |
| RMT(真实货币交易, Real Money Trading) | 很少 | 活跃 |
| 平台 | 游戏机 | PC, 移动设备 |
网络游戏的4种形式--物理结构 * 逻辑结构 物理结构有 C/S 和 P2P 两种, 逻辑结构有 MO 和 MMO 两种, 共有四种组合
表 2.4 网络游戏的4种形式及游戏类型
| MO | MMO | |
|---|---|---|
| C/S | 休闲游戏 | MMORPG 虚拟世界 |
| P2P | ARPG(动作类 RPG), 对战格斗游戏, FPS, 竞速游戏, RTS, 射击游戏 | N/A |
- 游戏的数据形式
- 游戏的通信方式
- 游戏的反应速度(延迟)
显示器每秒进行几十次的画面更新, 这种画面更新时间对玩家来说, 就是游戏状态变化的最短时间间隔
表 2.5 网络延迟与实现方法
| 名称 | 延迟 | 同步/异步 | 冗长 | 补充 | | ------| ------ | ------ | | 同步方式 | 25毫秒以下 | 同步 | 非冗余 | 在高速网络的前提下, 同步方式的实现方法比较好 | | 异步方式 | 100毫秒以下 | 非同步 | 冗余 | 为了在低速的网络上实现高速的游戏, 冗余性是必需的 | | 浏览器方式 | 300毫秒以下 | 非同步 | 非冗余 | 延迟的程度超出了用冗余性可以解决的范围, 所以将游戏数据和游戏客户端(游戏浏览器)完全分离 |
同步方式是指, 运行在所有游戏玩家设备上的程序是同步的, 星型拓扑下会有一个协调者来保证所有玩家在每一个单位时间(这个单位时间与帧速有关)内看到的状态是相同的, 只有获得了全体玩家的信息后, 游戏才能继续, 如果某个人的网络发生延迟, 同步速率就会变慢, 导致所有玩家都受影响.
异步方式是指, 各个终端上的游戏进行状态是不同的, 在游戏数据的一致性方面作出妥协, 不要求数据完全一致, 就算某台终端上的程序停止运行, 其他终端的程序也能照常运行, 但是会看到问题终端对应的角色出现卡死, 正因为如此, 在异步方式下可以使用更加不稳定的传输线路和延迟更大的线路, 也可以支持更多的同时在线数.
浏览器方式是指所有游戏内容都运行在后台, 前台只起到显示的作用, 这样即使服务器以外的所有程序都停止运行, 程序也能继续运行, 不会发生数据不匹配.
- 游戏处理的冗余化 --> 解决主数据和副本数据之间的关系
- 游戏处理的异步化 --> 解决数据变化时同步处理(锁)和异步处理之间的关系
游戏是按帧来处理的, 假设 1 秒钟有 60 帧, CPU 的主频是 1.79 MHz, 那么对于每一帧游戏画面, CPU 大约有 3 万个时钟周期可用(1790000/60 = 29666).
要让游戏世界中的物体移动起来, 必须进行以下处理: 读取坐标, 读取速度, 进行计算, 保存结果. 使用 6502 处理器的命令集处理以上操作需要 2~8 个周期, 假设在效率较高的程序中需要 4 个周期, 而且游戏场景中有 8 个物体, 那么要对二维坐标中 X, Y 两个数据各处理一次, 总共需要 (4 + 4 + 4 + 4) * 2 * 8 = 256 个周期, 相对于 CPU 3 万周期的处理能力可谓十分充裕.
接着需要判断己方子弹是否击中了敌人, 假设要对正在飞行的 8 个物体全部进行碰撞检测, 那么就必须进行 8 * 8 = 64 次检测, 碰撞检测不能根据两个物体的坐标是否一致来进行判断, 而是必须通过矩形来判断, 所以需要进行二次比较. 因此处理过程如下: 读取坐标, 二次比较, 判断结果. 这次没想处理需要 10 个周期, 又因为要处理 X, Y 坐标, 所以还要翻一倍, 最终需要 (10 + 10 + 10 + 10) * 2 * (8 * 8) = 5120 个周期, 再加上移动处理的 256 个周期, 也就 5400 个周期不好, 看上去还挺宽裕的.
家用游戏机上的经典游戏通常有 20 个左右的角色登场. 若对 20 个对象进行碰撞检测, 根据上面的计算方式, 需要 (10 + 10 + 10 + 10) * 2 * (20 * 20) = 32000 个周期, 这样就超过了 3 万周期的上限. 另外这里还没有考虑其他操作以及声音处理, 因此必须采取一些优化措施来降低所消耗的周期, 比如, 把"己方子弹之间不会发生碰撞", "敌方子弹与己方子弹不会发生碰撞" 等游戏内容考虑在内.
当 CPU 运算能力不足时, 游戏画面的刷新率就会降低, 导致游戏中物体的运动变得迟缓, 导致游戏体验急剧下降.
- 假设在家用游戏机中使用 RDBMS, 那么就必须通过 SQL 语句, 但是像 SELECT * from FlyingObjects 这样的语句, 单单判断语法是否正确就要消耗几百个 CPU 周期, 显然不现实. 游戏编程必须在 1 帧内完成坐标的判断和保存. 为此, 必须只通过组合 CPU 所具有的一些最原始的命令来实现, 只是读取数据就要花费几百个周期是相当不合理的. 因此, 在家用游戏机中, 基本不考虑使用 RDBMS 这种方式.
综合 3.1.4, 3.1.5, 3.1.6 , 游戏过程中的数据需要以非常快的速度不断变化, 所以这些数据必须在内存中进行管理. 在内存中进行管理的关键是注意 CPU 频率, 也就是要在几纳秒至几百纳秒的延迟内访问数据, 而光 1 纳秒也就前进 30 厘米的距离.
也就是说, 游戏数据需要存放在距离 CPU 数十厘米以内的地方, 但是在实际中, 玩家通常分散在各处, 所以必然要在较远处和较近处之间冗余地保存数据, 以此保证数据的一致性, 这一点非常困难.
为了尽可能的降低通信延迟, 实际使用的有星型, 和全网状结构(full mesh).
反射型只进行数据包的交换, 并不检查其中的内容.
P2P 架构有同步和异步两种方式, 同步方式有全网状结构和星型结构两种.
- MO(Multiplayer Online) 与 MMO(Massively Multiplayer Online) 的区别 MO 同时在线人数较少(2 - 100), 游戏时间相对较短, 没错开始游戏时, 游戏的状态都会被重置, 游戏数据的形式是一次性的. MMO 同时在线数量达到数百或数千, 游戏数据不能重置, 且是永久性的.
MO 架构经常在 FPS 和 RTS 等类型的游戏中使用, 适合那些在线人数较少, 实时性很高的游戏.
- MO 架构
- 同步方式/全网状结构
- 同步方式/星型结构
- 异步方式/全网状结构
- 异步方式/星型结构
同步方式/全网状结构, 参与游戏的所有终端都拥有主数据, 这些终端互相传输所有的控制设备输入信息, 在获得所有终端的输入数据之前, 游戏始终处于等待状态. 同步方式/星型结构, 配置一个综合管理游戏数据的根服务器, 所有参与游戏的终端将玩家的所有输入信息发送至服务器, 游戏状态一旦有所进展, 服务器就将那些改变了的状态数据返回给所有客户端, 在服务器返回信息之前, 所有的客户端都不进行任何渲染, 只是单纯的等待.
各终端之间只发送 "控制设备的输入信息", 游戏过程数据都是数字数据, 所以如果能毫无遗漏的发送初始状态及状态变化, 所有玩家的状态就能始终保持一致.
例子: 在线围棋游戏
同步方式/全网状结构的三个问题:
- 人数增加后, 收发信息的完整性极易崩溃, 特别是在网络不可靠的情况下
- 最慢的终端会拖长整体的传输时间
- 不能中途加入游戏
这种结构下, 网络中的所有成员并不是完全平等的, 星型结构的中央终端称为 "服务器", 其他终端则称为 "客户端". 客户端将控制设备上的方向键等输入信息发送至服务器, 服务器在接收完成后则将接收到的输入信息同时发送给所有客户端.
这种方式对数据传输链路的要求下降, 同时也引入了新的问题:
- 响应较慢(直连变成了转发).
同步方式不可避免的重大问题, 中途加入游戏会导致所有玩家暂时中断游戏, 因为新客户端需要获取状态数据. 解决方式是优先匹配物理位置相近的玩家(提高状态同步速度)或将游戏回合变短(不需要中途加入游戏).
分布式一致性算法不适用与该场景, 因为这种算法需要多次往返传输信息, 而采用异步方式的网络游戏需要在几十毫秒的这段极短的时间内保证数据一致.
- 物品复制问题
相对与"自己和对手", "自己和环境"来说不太重要, 能省就省
MMO 架构就是"在大量玩家之间共享长期存在的游戏过程", 对于这种游戏来说, 玩家投入了大量时间, 因此游戏系统必须具有很高的可靠性. MMO 架构中, 对游戏过程的管理和保存全部都由数据中心负责, 由数据中心持续的将游戏结果发送至玩家终端.
- MMO 游戏的特点:
- 玩家数据需要持久化
- 玩家数据会随着时间累积
- 支持大量玩家同时在线
-
浏览器方式, 同步方式和异步方式的差异 浏览器方式和同步方式的差异在于"传输的内容", 同步方式下收发的只有自己及其他玩家输入的信息, 而在浏览器方式下, 浏览器向服务器发送的是本地玩家的操作信息, 服务器向浏览器发送游戏世界中的结果. 此外, 在同步和异步方式下, 参与游戏的所有终端都共享游戏过程中的所有数据, 而在浏览器模式下, 管理游戏数据的只有服务器, 游戏逻辑全部都在服务器上实现, 各个终端(浏览器)只展现当前玩家操作在游戏世界中产生的结果.
-
MMO 架构的实现方针--浏览器方式(这里的浏览器不是指 web 浏览器), 纯粹的 C/S 模式
- 为了支持大量玩家同时在线, 必须放弃 MM 架构中的同步/异步方式(将游戏进行时的状态变化传输给所有的玩家).
- 大量玩家在线触发的巨量运算很容易就会导致服务器瘫痪, 因此, 为了支持更多的玩家同时在线, 必须对服务器进行减负. 客户端使用浏览器的方式实现, 只包含与渲染, 音效以及操作有关的处理, 仅将逻辑处理和玩家数据持久化放在服务器上. 客户端与服务器通信的数据量要尽可能的少, 并且能够忍受较大通信延迟和不稳定的连接. 就算不启动客户端, 游戏也会在服务器上持续运行.
- 因为所有的逻辑都是在服务器进行依次处理的, 所以玩家之间不会出现不一致的状态, 但是在通信延迟过长的情况下, 画面会变得不连贯
客户端与服务器的交互可以简化为: 客户端发送玩家操作 -> 服务器进行处理 -> 将处理结果显示在客户端
专栏--设法改善网页游戏的画面显示间隔
假设网络延迟为 200 毫秒, 实际移动需要 500 毫秒, 在网页游戏中事件的发生顺序为:
* 0 毫秒: 玩家开始移动(移动到坐标 XY 处)
* 0 毫秒: 操作信息开始向服务器发送
* 200 毫秒: 消息到达服务器
* 205 毫秒: 服务器处理结束, 将结果(移动开始)发送给客户端
* 405 毫秒: "移动开始" 的消息到达客户端, 开始进行渲染
* 905 毫秒: 移动画面渲染结束
在这种方式下, 玩家在操作后大约 400 毫秒之后, 角色才会开始移动, 从我们的感觉来看, 这种效果实在太差了, 只要将事件发生顺序更改为如下形式就能改善操作时的体验.
* 0 毫秒: 玩家开始移动(移动到坐标 XY 处)
* 0 毫秒: 操作信息开始向服务器发送
* 0 毫秒: 客户端并不等待服务器送来的结果信息, 立即开始渲染移动画面
* 200 毫秒: 消息到达服务器
* 205 毫秒: 服务器处理结束, 将结果(移动开始)发送给客户端
* 405 毫秒: "移动开始" 的消息到达客户端, 如果移动成功则忽略该消息
* 500 毫秒: 移动画面渲染结束
这样就将完成移动所需的 905 毫秒缩短到了 500 毫秒, 由此玩家就能感觉到自己的角色在很流畅的移动.
这里的问题是, 如果服务器发回了"移动失败"的消息, 就需要立即回到原本的位置, 否则游戏状态会不一致, 导致后续操作出现问题.
保证团队工作内容一致
| 类别 | 名称 | 目的 | 内容 |
|---|---|---|---|
| 策划文档 | 概要设计文档 | 用于让出资方判断项目可行性以及用于原型开发 | 包括游戏内容, 基本规则, 游戏主要元素, 平台以及商业模式 |
| 策划文档 | 详细设计文档(规格说明书) | 用于指导开发人员进行设计 | 此文档包含的信息与游戏攻略, 游戏说明中的内容相同. 以此为基础可以决定以怎样的方式编写代码, 如何开始进行设计工作. |
| 策划文档 | 开发要素/工作量列表 | 用于估算开发成本, 制定准确度较高的计划 | 罗列出所有必须实现的功能, 确定没有遗漏的状态, 对工作量进行量化 |
| 设计文档 | 系统基本结构图 | 服务器设计概要 | 为了进行进程关系图和资源的设计,将所需的设计方针可视化 |
| 设计文档 | 进程关系图 | 提高设计正确性, 筹备服务器, 构建系统 | 列出服务器及客户端的所有进程的信息, 包括进程数量, 关联性, 网络连接应有的状态, 连接顺序, 访问模式, 扩展方式 |
| 设计文档 | 服务器物理结构概要图 | 用于将如何配置服务器告知系统运维公司, 以及用于详细设计 | 以图形方式来说明具有某种特性的服务器必须以什么样的物理关系来配置 |
| 设计文档 | 带宽/设备资源估算文档 | 用于古色所需筹备的服务器, 传输线路, 存储设备等的成本 | 从技术层面上估算需要具备哪些类型的服务器, 各自需要多少台, 可用性需要达到何种程度 |
| 设计文档 | 协议定义文档 | 用于定义传输内容, 以及提高服务器和客户端并行开发的效率 | 记录了需要再客户端和服务器之间进行传输的数据包的内容 |
| 设计文档 | 数据库设计图 | 用于实现数据库 | 为了避免在运营之后突然出现数据库性能问题, 需要对数据库的查询语句进行规划 |
| 设计文档 | 系统运维设计文档 | 用于实际构建物理服务器系统 | 服务器需要具备怎样的性能, 应在何时购买, 购买几台, 如何进行配置, 连接, 设置 |
| 商业相关文档 | 合同 | 用于防范投资方, 开发方, 运营方出现交易纠纷 | |
| 商业相关文档 | 商业计划书 | 用于判断投资计划的可行性 | 根据过去的经验来预估初期开发, 乃至运营开始后 2-3 年之内的动向 |
| 商业相关文档 | 开发日程 | 用于把握整体的开发进度 | 开发计划的制定 |
| 商业相关文档 | 开发体制图 | 用于确认开发流程是否正常 | 对公司外部的人员说明己方的开发体制 |
C/S MMO 架构特点:
- 支持大量数据的处理
- 向玩家严格保密设定信息
- 严格维护游戏数据的更改内容, 屏蔽非法操作
- 简单的进行设定信息的更改
- 易于与其他服务系统结合
C/S MMO 架构限制:
- 延迟较大
- 游戏服务器带宽负荷很高
- 游戏服务器维护费用高
- 服务器维护期间无法进行游戏
输入:
- 确认期望的同时连接数
- 确认预期的系统瓶颈
- 空间分割法, 用来解决服务器瓶颈.
- 实例法(游戏副本实例), 将负荷特别高的, 用户集中在一起的部分独立出来, 将这些部分分配给专用的服务器来处理, 用来解决服务器瓶颈.
- 平行世界方式, 将游戏数据库分割为多个, 用来解决数据库瓶颈.
估算公式: 同时在线数 * 每个玩家所面对的敌人数 * 每秒敌人的行动次数 * 每次行动所需的 CPU 时间 * 安全系数 = 1秒
估算公式: 同时在线数 * 每个连接平均的数据存储频率 * 1 次存储所需的查询数 * 安全系数 = 数据库服务器支持的查询频率
| 名称 | 本书中的缩略语 | 用途 |
|---|---|---|
| 客户端 | cli | 用户直接使用的, 用于访问游戏服务器的专用程序 |
| 游戏服务器 | gmsv | 游戏逻辑的处理, 包括执行敌人的行动, 地形判断, 事件, 角色升级, 作弊检测 |
| 登录服务器 | loginsv | 负责服务整体使用情况的管理, 负荷的控制以及会话密钥的发放 |
| 数据库服务器 | dbsv | 对 MySQL 和 Oracle 等 DBMS 进行统一的连接 |
| 反向代理服务器 | proxy | 接受来自多个客户端的同时连接, 负责进行 TCP 会话本身的管理, 数据的解压缩以及解密, 减轻游戏服务器的负荷 |
| 消息服务器 | msgsv | 支撑网上聊天, 即时消息, 公会等社交活动 |
| 世界服务器 | worldsv | 使用空间分割的情况下, 属于该世界的所有 gmsv 连接至这个服务器进程, 负责各个世界共同需要的处理 |
| 通用数据库服务器 | commondbsv | 在使用平行世界的情况下, 对所有世界共同需要的信息进行持久化. 除了作为 msgsv 的后端, 还多用来进行实时统计处理和等级排名 |
| 收费认证服务器 | authsv | 与结算公司之间的网关 |
| 日志服务器 | logsv | 通过 TCP 收集整个服务器中的日志 |
| DBMS | DBMS | 数据库进程 |
| 结算公司服务器 | 结算sv | 结算公司所管理的服务器 |
- gmsv, loginsv, msgsv, proxy 这些靠近服务前方的进程称为 "前端", 除此之外都称为 "后端".
- 实现用来表示服务器的连接必不可少的线, 虚线表示即使切断也无所谓的线.
- 黑色四边形所示的部分表示在不使用中间件时, 必须自己制作, 灰色四边形表示使用 MySQL 等现成的程序
- 所有的 gmsv 都连接到 dbsv, authsv, worldsv 上
- backup 指通过单纯的复制来备份数据库
- gmsv 能增加到 3 个以上, 目标是 20~30 个
- 一个 gmsv 对应一个 proxy, 两个以上也可以
- msgsv 和 loginsv 各有一个就够了
- authsv 通常也不需要多个
进行估算时, 将服务器分为 "以 CPU 为中心的服务器" 和 "以存储为中心的服务器", 它们各自的特点如下:
- 以 CPU 为中心的服务器: CPU 较快, 内核较多, 内存一般, 存储量小, 容错性低, 一次性的
- 以存储为中心的服务器: CPU 一般, 内核一般, 内存高, 存储量大, 容错性高, 使用期长
带宽的估算基于每个客户端正常运行所需的平均数据量
所有进程间通信基本上都是采用基于 TCP 的 RPC, 只要能对 "进程之间的通信以怎样的顺序调用怎么的函数" 进行定义, 就能完成协议的定义了. 协议是无状态和简单操作的集合.
优秀的 API 调用时序:
- 数据结构优先原则
- 维持可玩状态原则
- 后端服务器延后开发原则
- 持续测定原则(开发过程中不断度量系统的性能数据)
视频游戏中的数据分类包括 "基本不会变化的部分" 和 "频繁变化的部分", 一般游戏中物体用 列表 + Rtree 的方式来表示.
Rtree 用于二维和多维数据的索引, 它是一种多级平衡树, 是 Btree 在多维空间上的扩展. 在 Rtree 中存放的数据并不是原始数据, 而是这些数据的最小边界矩形(Minimal-Bounding-Box, MBR).
这类游戏状态频繁发生变化, 会产生大量数据交互, 如果使用 C/S 方式实现, 对服务器, 带宽等成本要求过高, 所以从商业角度来考虑是不行的. 因此, 即使有使用游戏外挂作弊的风险, P2P 的实现方式从经济角度来说也是合理的. "同步共享内存是" P2P MO 游戏开发中经常使用的特有方法.
RPC 开发方式和共享内存开发方式的比较
| RPC 开发方式 | 共享内存开发方式 | |
|---|---|---|
| 通信量 | 最小限度 | 会有多余的通信 |
| CPU 负荷 | 最小限度 | 少量多余的运算量 |
| 最大同时连接 | 数千 | 数十到100 |
| 开发难易度 | 复杂 | 简单但是代码量大 |
| 通信延迟 | 没有区别 | 没有区别 |
| 游戏类型 | 即时性低 | 即时性高 |
| 游戏数据规模 | 数据量大(对象数百万以上) | 数据量小(对象几百到几千) |
| 通信方式 | 一对多 | 一对全部 |
| 数据同步的开发时机 | 在最开始需要开发 | 可以在单机版之后扩展 |
- 不需要大量的数据交互
- 配置信息对玩家是可见的
- 不能严格保证游戏数据变更的安全性(可以作弊)
- 不能进行 P2P 连接的 NAT 网络环境有很多
- 不能简单的更新游戏
- 不方便结合社交网络等网络服务
- 玩家掉线的情况比较多
- 延迟较少
- 游戏服务器的带宽负荷低(甚至没有负荷)
- 游戏服务器硬件成本低(甚至零成本)
- 服务器维护期间也可以正常进行游戏
P2P MO 类型游戏没有专门的服务器, 所有玩家只与共同游戏的客户端通信
C/S MMO 类型的游戏, 包含的进程有客户端程序, 游戏服务器, 登录服务器, 验证服务器和数据库服务器, 但是对于 P2P MO 游戏来说, 只有游戏客户端一种, 所以可以不用制作系统关系图的资料.
-
星型拓扑结构还是网状拓扑结构 星型拓扑结构与网状拓扑结构的区别在于, 共享客户端数据所需的链路跳数. 星型拓扑结构是 2(需要通过节点转发), 网状拓扑结构是 1(直连). 网状拓扑虽然延时较小, 但是节点间可能有不能通信的问题. 所以在不追求速度的情况下, 选择采用星型拓扑. 星型拓扑中的转发节点可能引入单点故障, 此时选举其他节点为新的转发节点.
-
同步, 非同步还是浏览器方式实现 因为游戏基于互联网通信, 考虑网络的复杂性和不稳定性, 排除同步方式, 另外因为游戏不需要支持大量用户, 所以决定采用异步的方式实现
顾名思义, 共享内存就是将相同的内存数据共享给不同的进程, 需要共享的具体数据包括可动物体的坐标, 种类以及移动方向等信息.
共享内存方式的注意点:
- 竞争状态
- 加锁处理
RPC 开发方式--C/S MMO 游戏采用的 RPC 开发方式按照下列顺序更新游戏进度数据:
- 玩家在客户端(程序)进行角色移动的操作.
- 客户端向服务器端发送操作的 RPC 请求.
- 服务器接收到 move(5, 5) 函数的请求后, 首先检测参数 (5, 5) 是否正确, 如果正确就在游戏进度数据中将角色的位置坐标更新为 (5, 5).
- 服务器更新数据成功后, 将新的值同步到其他客户端.
采用 RPC 开发方式时, 网络上传输的是 "变更的请求", 而不是 "变更的结果".
共享内存开发方式--P2P MO 游戏 P2P MO 游戏采用的共享内存开发方式要求客户端和服务器端共享相同的游戏数据, 在这个前提下按照下列顺序处理游戏数据.
- 玩家在客户端(程序)进行角色移动的操作.
- 客户端检测移动操作是否正确, 如果没有问题则更新本机管理的游戏进度数据.
- 客户端将更新后的数值传输给其他客户端.
- 其他客户端无推荐接收更新后的数据.
采用共享内存方式时, 网络上传输的是 "变更的结果", 而不是 "变更的请求", 所以只需要无条件替换对应的数值.
共享内存更容易进行细微的修改, 有利于追求更高品质的优点, 缺点是即使只有少数几个数值发生了变化也需要进行通信,这样可能会产生一些多余的通信量.
解决 P2P MO 游戏玩家不能互联的问题


















