游戏服务器端开发要点
2015年11月17日 11:16
0 点赞
0 评论
更新于 2025-11-21 19:25
一、专业基础
1.1 网络
1.1.1 理解 TCP/IP 协议
- 网络传输模型:深入了解网络传输模型,它是网络通信的基础架构,为数据在网络中的传输提供了规范和框架。
- 滑动窗口技术:掌握滑动窗口技术,该技术用于控制数据传输的流量,确保发送方和接收方的数据处理能力相匹配,提高传输效率。
- 建立连接的三次握手与断开连接的四次握手:熟悉 TCP 连接建立的三次握手和断开连接的四次握手过程,这是保证数据可靠传输的关键环节。
- 连接建立与断开过程中的各种状态:了解连接建立与断开过程中各个状态的含义和作用,如 SYN_SENT、ESTABLISHED、FIN_WAIT_1 等,有助于排查网络连接问题。
- TCP/IP 协议的传输效率:研究 TCP/IP 协议的传输效率,包括影响传输效率的因素,如带宽、延迟、拥塞控制等。
思考:
- 请解释 DOS 攻击与 DRDOS 攻击的基本原理。DOS(Denial of Service)攻击是指攻击者通过向目标服务器发送大量的请求,使服务器资源耗尽,无法正常响应合法用户的请求。DRDOS(Distributed Reflection Denial of Service)攻击是一种分布式反射拒绝服务攻击,攻击者利用大量的反射源向目标服务器发送伪造的请求,从而放大攻击效果。
- 一个 100Byte 数据包,精简到 50Byte,其传输效率提高了多少?在理想情况下,传输效率提高的比例需要考虑多种因素,如网络带宽、延迟、协议开销等,不能简单地认为传输效率提高了 50%。
- TIMEWAIT 状态怎么解释?TIMEWAIT 状态是 TCP 连接断开过程中的一个状态,当一方发送 FIN 包后,进入 FIN_WAIT_1 状态,收到对方的 ACK 包后进入 FIN_WAIT_2 状态,当对方发送 FIN 包后,发送 ACK 包并进入 TIMEWAIT 状态。TIMEWAIT 状态的存在是为了确保最后一个 ACK 包能够被对方收到,同时避免在该连接上出现旧的数据包。
1.1.2 掌握常用的网络通信模型
- Select:了解 Select 模型,它是一种基于轮询的网络通信模型,通过不断地轮询文件描述符集合,判断哪些文件描述符有数据可读或可写。
- Epoll:掌握 Epoll 模型,它是 Linux 下的一种高效的网络通信模型,采用事件驱动的方式,避免了 Select 模型的轮询开销。同时,要了解 Epoll 的边缘触发和水平触发的区别与应用场景。
- Select 与 Epoll 的区别及应用:对比 Select 和 Epoll 的优缺点,根据具体的应用场景选择合适的网络通信模型。Select 适用于连接数较少的场景,而 Epoll 适用于连接数较多且并发较高的场景。
1.2 存储
- 计算机系统存储体系:了解计算机系统的存储体系,包括寄存器、高速缓存、内存、硬盘等,掌握不同存储层次的特点和作用。
- 程序运行时的内存结构:熟悉程序运行时的内存结构,如代码段、数据段、堆、栈等,理解内存分配和释放的原理。
- 计算机文件系统,页表结构:掌握计算机文件系统的基本原理,如 FAT、NTFS、EXT 等,了解页表结构在虚拟内存管理中的作用。
- 内存池与对象池的实现原理,应用场景与区别:理解内存池和对象池的实现原理,它们是为了减少内存分配和释放的开销而设计的。掌握它们的应用场景和区别,内存池适用于频繁分配和释放小块内存的场景,而对象池适用于频繁创建和销毁对象的场景。
- 关系数据库 MySQL 的使用:熟练掌握关系数据库 MySQL 的使用,包括数据库的创建、表的设计、SQL 语句的编写等。
- 共享内存:了解共享内存的概念和使用方法,共享内存是一种高效的进程间通信方式,多个进程可以直接访问同一块物理内存。
1.3 程序
- 对 C/C++ 语言有较深的理解:具备扎实的 C/C++ 语言基础,熟悉 C/C++ 的语法、特性和编程规范。
- 深刻理解接口,封装与多态,并且有实践经验:理解接口、封装和多态的概念,掌握它们在面向对象编程中的应用。通过实际项目经验,学会如何运用这些特性提高代码的可维护性和可扩展性。
- 深刻理解常用的数据结构:熟悉常用的数据结构,如数组、链表、二叉树、哈希表等,掌握它们的实现原理和应用场景。
- 熟悉常用的算法及相关复杂度:了解常用的算法,如冒泡排序、快速排序等,掌握算法的时间复杂度和空间复杂度分析方法。
二、游戏开发入门
2.1 防御式编程
- 不要相信客户端数据,一定要进行检验。作为服务器端,无法确定客户端的身份和意图,因此必须做好自我保护。对函数的传入参数和返回值进行合法性判断,确保数据的有效性。内部子系统和功能模块之间应保持低耦合、高内聚,避免过度信任。
- 采用插件式的模块设计,使模块功能的健壮性内建于模块本身,尽量减少模块间的耦合。这是判断一个服务器端程序员是否入门的基本标准。
2.2 设计模式
- 不要迷信和迷恋设计模式,更不要生搬硬套。应遵循“道法自然”的原则,用最简单的办法解决问题。正如“设计本天成,妙手偶得之”,设计模式应根据具体的需求和场景灵活运用。
2.3 网络模型
- 自造轮子:思考 Select 和 Epoll 模型,Epoll 并不一定在所有情况下都比 Select 高效,需要根据具体的应用场景进行选择。
- 开源框架:了解开源框架 Libevent、libev 和 ACE,这些框架提供了高效的网络编程接口,可以提高开发效率。
2.4 数据持久化
- 自定义文件存储:如《梦幻西游》采用的自定义文件存储方式,适用于对数据存储格式有特殊要求的场景。
- 关系数据库:使用 MySQL 作为关系数据库,它具有成熟的技术和广泛的应用,适合存储结构化数据。
- NO - SQL 数据库:选择 MongoDB 作为 NO - SQL 数据库,它具有高可扩展性和灵活的数据模型,适合存储非结构化数据。
- 选择存储系统要考虑的因素:选择存储系统时,需要考虑稳定性、性能和可扩展性等因素。
2.5 内存管理
- 使用内存池和对象池,禁止在运行期间动态分配内存,以减少内存碎片和提高内存分配效率。
- 对于输入输出的指针参数,要进行严格检查,确保指针的有效性。
- 采用带内存保护的函数,如 strncpy、memcpy、snprintf、vsnprintf 等,防止数组下标越界和内存溢出。确保字符串以 '\0' 结束,防止读内存溢出。
2.6 日志系统
- 简单高效:日志系统应简单高效,大量的日志操作不应影响程序性能。
- 稳定:确保服务器崩溃时日志不丢失,可采用异步写入或定期备份等方式。
- 完备:记录玩家的关键操作日志,理想情况下,通过日志能重建任何时刻的玩家数据。
- 开关:开发日志应添加级别开关控制,方便在不同的开发阶段进行日志管理。
2.7 通信协议
- PDL(Protocol Design Language):采用 PDL 如 Protobuf,可以同时生成前后端代码,减少前后端协议联调成本,且具有良好的扩展性。
- JSON:JSON 是一种文本协议,简单、自解释,无联调成本,扩展性好,方便进行包过滤和写日志。
- 自定义二进制协议:自定义二进制协议具有精简、高效的传输性能,完全可控,但几乎无扩展性。
2.8 全局唯一 Key(GUID)
- 为合服做准备,每个角色、装备、道具都应对应有全局唯一 Key,方便追踪道具和装备的流向。
2.9 多线程与同步
使用消息队列进行同步化处理,确保多线程环境下数据的一致性和安全性。
2.10 状态机
- 强化角色的状态管理,对前置状态进行检查校验,确保角色状态的正确转换。
2.11 数据包操作
- 合并:将同一帧内的数据包进行合并,减少 IO 操作次数,提高性能。
- 单副本:用一个包尽量只保存一份数据,减少内存复制次数。
- AOI 同步:在 AOI 同步中减少中间过程无用数据包,降低网络带宽消耗。
2.12 状态监控
随时监控服务器内部状态,包括内存池和对象池的使用情况、帧处理时间、网络 IO、包处理性能和各种业务逻辑的处理次数等。
2.13 包频率控制
基于每个玩家每条协议的包频率控制,可有效瘫痪变速齿轮等作弊工具。
2.14 开关控制
每个模块都应设置开关,以便在出现问题时能够紧急关闭任何功能模块。
2.15 反外挂反作弊
- 包频率控制:可以消灭变速齿轮等作弊工具。
- 包 id 自增校验:可以消灭 WPE 等作弊工具。
- 包校验码:可以防止包拦截篡改。
- 图形识别:可以踢掉 99% 非人的操作。要认识到“魔高一尺,道高一丈”,不断更新反作弊手段。
2.16 热更新
- 核心配置逻辑的热更新:如防沉迷系统、包频率控制、开关控制等核心配置逻辑应支持热更新。
- 代码基本热更新:采用 Erlang、Lua 等语言实现代码的基本热更新,减少服务器停机时间。
2.17 防刷
- 记录关键系统资源(如元宝、精力值、道具、装备等)的产出日志,便于后续审计和排查。
- 资源的产出和消耗尽量依赖两个或以上的独立条件的检测,增加刷取难度。
- 严格检查各项操作的前置条件,校验参数合法性,防止非法刷取。
2.18 防崩溃
- 系统底层与具体业务逻辑无关,可使用大量的机器人进行压力测试,暴露各种 bug,确保系统稳定。
- 业务逻辑建议使用脚本实现,提高代码的可维护性和灵活性,系统性地保证游戏不会崩溃。
2.19 性能优化
- IO 操作异步化:将 IO 操作异步化,提高程序的并发性能。
- IO 操作合并缓写:采用事务性的提交 db 操作、包合并、文件日志缓写等方式,减少 IO 操作次数。
- Cache 机制:使用 Cache 机制,减少对数据库或文件系统的访问,提高数据读取速度。
- 减少竞态条件:避免频繁进出切换,尽量减少锁定使用,多线程不一定比单线程快,要根据具体情况进行选择。
- 减少内存复制:优化代码,减少不必要的内存复制操作。
- 自己测试,用数据说话:通过实际测试,收集性能数据,根据数据进行优化,而不是凭猜测进行优化。
2.20 运营支持
- 接口支持:提供实时查询、控制指令、数据监控、客服处理等接口,方便运营人员进行管理。
- 实现考虑提供 Http 接口:考虑实现 Http 接口,便于与其他系统进行集成。
2.21 容灾与故障预案
略
三、服务器端架构
3.1 什么是好的架构?
- 满足业务要求:架构应能够满足游戏业务的需求,支持游戏的各种功能和玩法。
- 能迅速的实现策划需求,响应需求变更:具备快速响应策划需求和变更的能力,确保游戏的开发进度和灵活性。
- 系统级的稳定性保障:提供系统级的稳定性保障,确保服务器在高并发情况下稳定运行。
- 简化开发:将复杂性控制在架构底层,降低对开发人员的技术要求。逻辑开发不依赖于开发人员本身强大的技术实力,提高开发效率。
- 完善的运营支撑体系:具备完善的运营支撑体系,方便运营人员进行管理和维护。
3.2 架构实践的思考
- 简单,满足需求的架构就是好架构:架构设计应遵循简单原则,避免过度设计,只要能够满足需求就是好的架构。
- 设计性能,抓住重要的 20%:在架构设计中,抓住重要的 20% 的性能瓶颈进行优化,没必要从程序代码里面去抠性能。
- 热更新是必须的:热更新功能可以减少服务器停机时间,提高用户体验,因此是架构设计中必须考虑的因素。
- 人难免会犯错,尽可能的用一套机制去保障逻辑的健壮性:通过设计一套完善的机制,如错误处理、容错机制等,保障逻辑的健壮性,减少人为错误对系统的影响。
转载自网络