本书主要讲述大型多人在线游戏开发的框架与编程实战,以实例的形式讲解从零开始制作网络游戏框架的完整过程,让读者了解网络游戏制作中的所有细节。最终得到一个完整的、基于ECS模式的、高效的分布式服务端框架,一个可以登录的客户端以及用于验证网络游戏各个模块功能的自动化测试系统。
全书共12章,从网络游戏的底层网络编程开始,逐步引导读者深入网络游戏开发的各个步骤。通过近50个真实示例、90个流程图,以直观的方式阐述和还原游戏制作的全过程,涵盖网络游戏设计的核心概念和实现:游戏主循环、线程、Actor模式、定时器、对象池、组件编码、架构层的解耦等。
封面图
目录
- 前言
- 第1章 网络编程基础1
- 1.1 单机游戏与网络游戏的区别1
- 1.2 理解IP地址4
- 1.3 理解TCP/IP5
- 1.4 阻塞式网络编程7
- 1.4.1 工程源代码7
- 1.4.2 服务端代码分析9
- 1.4.3 客户端代码分析13
- 1.4.4 系统差异14
- 1.4.5 网络底层函数说明14
- 1.4.6 小结17
- 1.5 非阻塞网络编程17
- 1.5.1 工程源代码18
- 1.5.2 服务端代码分析19
- 1.5.3 客户端代码分析21
- 1.5.4 小结23
- 1.6 总结24
- 第2章 网络IO多路复用25
- 2.1 Select网络模型25
- 2.1.1 ::select函数说明25
- 2.1.2 工程源代码27
- 2.1.3 网络基类:Network29
- 2.1.4 NetworkListen分析31
- 2.1.5 Server流程详解35
- 2.1.6 NetworkConnector分析37
- 2.1.7 测试流程详解39
- 2.1.8 ConnectObj分析41
- 2.1.9 Buffer分析42
- 2.1.10 RecvNetworkBuffer分析44
- 2.1.11 SendNetworkBuffer分析48
- 2.1.12 Packet分析50
- 2.1.13 小结55
- 2.2 Epoll网络模型55
- 2.2.1 函数说明56
- 2.2.2 源代码分析57
- 2.2.3 小结60
- 2.3 网络协议:protobuf61
- 2.3.1 在Windows下编译使用protobuf62
- 2.3.2 在Linux下编译使用protobuf64
- 2.3.3 使用protobuf定义协议66
- 2.4 总结69
- 第3章 线程、进程以及Actor模型70
- 3.1 游戏架构概述70
- 3.1.1 无服务端游戏70
- 3.1.2 单进程CS架构71
- 3.1.3 多进程CS架构71
- 3.2 框架瓶颈72
- 3.2.1 滚服游戏72
- 3.2.2 副本游戏73
- 3.2.3 大图分割空间游戏73
- 3.3 设计游戏框架74
- 3.4 游戏主循环76
- 3.5 理解进程和线程77
- 3.5.1 进程是什么77
- 3.5.2 线程是什么78
- 3.5.3 C++标准线程库79
- 3.6 Actor模型82
- 3.7 游戏框架中的线程84
- 3.7.1 包裹类ThreadObject85
- 3.7.2 线程类Thread85
- 3.7.3 线程管理类ThreadMgr86
- 3.7.4 libserver库与游戏逻辑88
- 3.8 Actor对象之间的消息处理机制92
- 3.8.1 消息定义原则93
- 3.8.2 消息队列机制94
- 3.9 总结99
- 第4章 账号登录与验证100
- 4.1 登录流程图100
- 4.2 制作一个简单的验证接口101
- 4.2.1 Nginx参考配置102
- 4.2.2 php-fpm参考配置103
- 4.3 导入PHP登录接口104
- 4.3.1 修改PHP中的数据库配置104
- 4.3.2 导入测试账号105
- 4.3.3 批量生成账号105
- 4.4 编码中用到的第三方库106
- 4.4.1 库libcurl106
- 4.4.2 库libjsoncpp107
- 4.5 账号验证代码分析108
- 4.5.1 定义登录协议号108
- 4.5.2 处理协议的Account类110
- 4.5.3 Account类如何放置到线程中110
- 4.5.4 处理验证的HttpRequestAccount类112
- 4.6 结果测试115
- 4.7 消息过滤机制116
- 4.8 测试机器人118
- 4.8.1 状态机119
- 4.8.2 状态机基类120
- 4.8.3 状态机管理类120
- 4.8.4 Robot类中的状态机122
- 4.9 批量登录测试125
- 4.10 总结126
- 第5章 性能优化与对象池127
- 5.1 Visual Studio性能工具127
- 5.2 内存中的数据结构131
- 5.2.1 交换型数据结构131
- 5.2.2 刷新型数据结构135
- 5.3 gprof137
- 5.3.1 gprof调用堆栈图138
- 5.3.2 让进程安全退出139
- 5.3.3 用gprof工具查看框架141
- 5.4 valgrind145
- 5.5 对象池150
- 5.5.1 对象池代码分析150
- 5.5.2 使用cmd命令查看对象池154
- 5.6 总结155
- 第6章 搭建ECS框架156
- 6.1 一个简单的ECS工程156
- 6.1.1 组件类Component157
- 6.1.2 实体类Entity158
- 6.1.3 系统类System158
- 6.1.4 管理类EntitySystem159
- 6.1.5 测试161
- 6.2 基于ECS框架的libserver162
- 6.2.1 通过字符串动态创建类163
- 6.2.2 提供多参变量来创建实例168
- 6.2.3 EntitySystem的工作原理171
- 6.3 基于ECS框架的login和robots工程177
- 6.3.1 Account类177
- 6.3.2 动态创建组件或实例178
- 6.3.3 ECS框架下的网络通信185
- 6.3.4 执行效率188
- 6.4 YAML文件189
- 6.4.1 YAML编译安装189
- 6.4.2 读取YAML配置文件191
- 6.4.3 合并线程195
- 6.5 log4cplus日志197
- 6.5.1 log4cplus的编译安装197
- 6.5.2 配置文件198
- 6.5.3 使用log4cplus200
- 6.6 总结202
- 第7章 MySQL数据库203
- 7.1 MySQL Connector/C203
- 7.2 连接时使用的函数说明204
- 7.3 数据库连接组件206
- 7.3.1 MysqlConnector组件206
- 7.3.2 连接数据库206
- 7.3.3 关闭连接207
- 7.4 写入数据时使用的函数说明208
- 7.5 写入数据示例209
- 7.5.1 创建预处理209
- 7.5.2 用预处理创建角色211
- 7.6 查询数据时使用的函数说明215
- 7.7 查询数据示例216
- 7.7.1 Query查询函数216
- 7.7.2 查询玩家数据217
- 7.8 数据表的创建与更新219
- 7.8.1 创建表221
- 7.8.2 更新表224
- 7.8.3 测试更新与创建组件225
- 7.9 数据表中的数据结构与protobuf结构227
- 7.10 角色查询与创建流程229
- 7.10.1 为login进程与dbmgr进程创建连接类229
- 7.10.2 找到指定的NetworkConnector实例230
- 7.10.3 创建角色232
- 7.10.4 机器人登录创建角色测试232
- 7.11 总结233
- 第8章 深入学习组件式编程234
- 8.1 新的系统管理类SystemManager234
- 8.1.1 实体系统EntitySystem236
- 8.1.2 更新系统UpdateSystem238
- 8.1.3 消息系统MessageSystem240
- 8.1.4 测试执行效率242
- 8.2 allinone工程242
- 8.2.1 新工程allinone243
- 8.2.2 协议是如何被转发的244
- 8.2.3 查看线程中的所有对象247
- 8.2.4 测试执行效率248
- 8.3 线程分类248
- 8.4 IAwakeSystem接口与对象池251
- 8.4.1 DynamicObjectPoolCollector对象池集合252
- 8.4.2 全局单例对象253
- 8.4.3 查看线程中的所有对象255
- 8.5 主动销毁对象258
- 8.5.1 一般组件销毁258
- 8.5.2 引用计数销毁对象259
- 8.6 时间堆262
- 8.6.1 堆实现代码264
- 8.6.2 时间堆组件265
- 8.7 总结270
- 第9章 服务器管理进程与HTTP271
- 9.1 启动多个login进程271
- 9.2 appmgr进程272
- 9.3 HTTP275
- 9.4 使用Mongoose分析HTTP格式277
- 9.4.1 HTTP类型278
- 9.4.2 接收HTTP数据279
- 9.4.3 处理HTTP数据的协议号282
- 9.4.4 收到HTTP请求是如何响应的283
- 9.4.5 发送HTTP返回数据流程286
- 9.5 为Packet定义新的网络标识287
- 9.5.1 使用网络标识创建一个连接289
- 9.5.2 使用网络标识发送数据291
- 9.5.3 向外部请求HTTP数据293
- 9.6 HTTP分块295
- 9.7 机器人测试批量登录297
- 9.8 总结300
- 第10章 分布式登录与Redis内存数据库301
- 10.1 game与space的定位301
- 10.1.1 选择合适的game进程305
- 10.1.2 使用token登录game进程307
- 10.1.3 Player组件308
- 10.2 Redis及其第三方库309
- 10.2.1 Redis的安装310
- 10.2.2 Redis 命令行命令311
- 10.2.3 hireids库312
- 10.2.4 组件RedisConnector314
- 10.2.5 Redis在login中的应用317
- 10.2.6 Redis在game中的应用323
- 10.2.7 从Redis删除数据325
- 10.3 性能瓶颈分析327
- 10.3.1 使用日志查看瓶颈327
- 10.3.2 优化MessageComponent组件329
- 10.3.3 ConnectObj内存组织331
- 10.4 多进程登录协议回顾332
- 10.5 总结334
- 第11章 分布式跳转方案335
- 11.1 资源数据配置与读取335
- 11.1.1 资源管理类ResourceManager336
- 11.1.2 地图资源管理类ResourceWorldMgr337
- 11.1.3 地图资源类ResourceWorld340
- 11.2 地图类World与代理类WorldProxy343
- 11.2.1 地图类World344
- 11.2.2 为什么需要WorldProxy350
- 11.3 分布式地图跳转流程351
- 11.3.1 发起跳转协议的时机353
- 11.3.2 跳转协议的数据定义353
- 11.3.3 目标代理地图收到跳转协议356
- 11.3.4 网络标识如何在网络中传递357
- 11.3.5 space进程发送的协议如何转发到客户端360
- 11.4 通过客户端进入游戏363
- 11.5 玩家在WorldProxy之间的跳转367
- 11.6 总结374
- 第12章 断线与动态加载系统375
- 12.1 玩家断线375
- 12.1.1 玩家在login进程中断线376
- 12.1.2 玩家在game进程中断线376
- 12.1.3 玩家断线时World类的处理377
- 12.1.4 玩家数据的读取与保存377
- 12.1.5 如何进入断线之前的地图381
- 12.2 进程之间的断线382
- 12.2.1 login进程断线与重连382
- 12.2.2 game进程断线与重连383
- 12.2.3 space进程断线与重连385
- 12.2.4 appmgr进程断线与重连387
- 12.3 动态新增系统389
- 12.3.1 MoveComponent组件389
- 12.3.2 新系统MoveSystem391
- 12.3.3 加载新系统392
- 12.3.4 测试移动394
- 12.4 总结395
- 写在最后——如何构建自己的框架396