服务器端开发的一些建议

摘要: 本文作为游戏服务器端开发的基本大纲,是游戏实践开发中的总结。第一部分专业基础,用于指导招聘和实习考核, 第二部分游戏入门,讲述游戏服务器端开发的基本要点,第三部分服务端架构,介绍架构设计中的一些基本原则。希望能帮到大家

一 专业基础

1.1 网络

1.1.1 理解TCP/IP协议
网络传输模型
滑动窗口技术
建立连接的三次握手与断开连接的四次握手
连接建立与断开过程中的各种状态
TCP/IP协议的传输效率
思考
1)请解释DOS攻击与DRDOS攻击的基本原理
2)一个100Byte数据包,精简到50Byte, 其传输效率提高了50%
3)TIMEWAIT状态怎么解释?
1.1.2 掌握常用的网络通信模型
Select
Epoll,边缘触发与平台出发点区别与应用
Select与Epoll的区别及应用
1.2 存储
计算机系统存储体系
程序运行时的内存结构
计算机文件系统,页表结构
内存池与对象池的实现原理,应用场景与区别
关系数据库MySQL的使用
共享内存
1.3 程序
对C/C++语言有较深的理解
深刻理解接口,封装与多态,并且有实践经验
深刻理解常用的数据结构:数组,链表,二叉树,哈希表
熟悉常用的算法及相关复杂度:冒泡排序,快速排序

二 游戏开发入门

2.1防御式编程
不要相信客户端数据,一定要检验。作为服务器端你无法确定你的客户端是谁,你也不能假定它是善意的,请做好自我保护。(这是判断一个服务器端程序员是否入门的基本标准)
务必对于函数的传人参数和返回值进行合法性判断,内部子系统,功能模块之间不要太过信任,要求低耦合,高内聚
插件式的模块设计,模块功能的健壮性应该是内建的,尽量减少模块间耦合
2.2 设计模式
道法自然。不要迷信,迷恋设计模式,更不要生搬硬套
简化,简化,再简化,用最简单的办法解决问题
借大宝一句话:设计本天成,妙手偶得之
2.3 网络模型
自造轮子: Select, Epoll, Epoll一定比Select高效吗?
开源框架: Libevent, libev, ACE
2.4 数据持久化
自定义文件存储,如《梦幻西游》
关系数据库: MySQL
NO-SQL数据库: MongoDB
选择存储系统要考虑到因素:稳定性,性能,可扩展性
2.5 内存管理
使用内存池和对象池,禁止运行期间动态分配内存
对于输入输出的指针参数,严格检查,宁滥勿缺
写内存保护。使用带内存保护的函数(strncpy, memcpy, snprintf, vsnprintf等),严防数组下标越界
防止读内存溢出,确保字符串以’\0’结束
2.6 日志系统
简单高效,大量日志操作不应该影响程序性能
稳定,做到服务器崩溃是日志不丢失
完备,玩家关键操作一定要记日志,理想的情况是通过日志能重建任何时刻的玩家数据
开关,开发日志的要加级别开关控制
2.7 通信协议
采用PDL(Protocol Design Language), 如Protobuf,可以同时生成前后端代码,减少前后端协议联调成本, 扩展性好
JSON,文本协议,简单,自解释,无联调成本,扩展性好,也很方便进行包过滤以及写日志
自定义二进制协议,精简,有高效的传输性能,完全可控,几乎无扩展性
2.8 全局唯一Key(GUID)
为合服做准备
方便追踪道具,装备流向
每个角色,装备,道具都应对应有全局唯一Key
2.9 多线程与同步
消息队列进行同步化处理
2.10 状态机
强化角色的状态
前置状态的检查校验
2.11 数据包操作
合并, 同一帧内的数据包进行合并,减少IO操作次数
单副本, 用一个包尽量只保存一份,减少内存复制次数
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操作合并缓写 (事务性的提交db操作,包合并,文件日志缓写)
Cache机制
减少竞态条件 (避免频繁进出切换,尽量减少锁定使用,多线程不一定由于单线程) 多线程不一定比单线程快
减少内存复制
自己测试,用数据说话,别猜
2.20 运营支持
接口支持:实时查询,控制指令,数据监控,客服处理等
实现考虑提供Http接口
2.21 容灾与故障预案

三 服务器端架构

3.1 什么是好的架构?
满足业务要求
能迅速的实现策划需求,响应需求变更
系统级的稳定性保障
简化开发。将复杂性控制在架构底层,降低对开发人员的技术要求,逻辑开发不依赖于开发人员本身强大的技术实力,提高开发效率
完善的运营支撑体系
3.2 架构实践的思考
简单,满足需求的架构就是好架构
设计性能,抓住重要的20%, 没必要从程序代码里面去抠性能
热更新是必须的
人难免会犯错,尽可能的用一套机制去保障逻辑的健壮性

游戏服务器的设计是一项颇有挑战性的工作,游戏服务器的发展也由以前的单服结构转变为多服机构,甚至出现了bigworld引擎的分布式解决方案,最近了解到Unreal的服务器解决方案atlas也是基于集群的方式。

负载均衡是一个很复杂的课题,这里暂不谈bigworld和atlas的这类服务器的设计,更多的是基于功能和场景划分服务器结构。

首先说一下思路,服务器划分基于以下原则:

  1. 分离游戏中占用系统资源(cpu,内存,IO等)较多的功能,独立成服务器。
  2. 在同一服务器架构下的不同游戏,应尽可能的复用某些服务器(进程级别的复用)。
  3. 以多线程并发的编程方式适应多核处理器。
  4. 宁可在服务器之间多复制数据,也要保持清晰的数据流向。
  5. 主要按照场景划分进程,若需按功能划分,必须保持整个逻辑足够的简单,并满足以上1,2点。

服务器结构图:

游戏服务器架构拓扑图

各个服务器的简要说明:

Gateway 是应用网关,主要用于保持和client的连接,该服务器需要2种IO,对client采用高并发连接,低吞吐量的网络模型,如IOCP等,对服务器采用高吞吐量连接,如阻塞或异步IO。

网关主要有以下用途:

  1. 分担了网络IO资源
  2. 同时,也分担了网络消息包的加解密,压缩解压等cpu密集的操作。
  3. 隔离了client和内部服务器组,对client来说,它只需要知道网关的相关信息即可(ip和port)。
  4. client由于一直和网关保持常连接,所以切换场景服务器等操作对client来说是透明的。
  5. 维护玩家登录状态。

World Server 是一个控制中心,它负责把各种计算资源分布到各个服务器,它具有以下职责:

  1. 管理和维护多个Scene Server。
  2. 管理和维护多个功能服务器,主要是同步数据到功能服务器。
  3. 复杂转发其他服务器和Gateway之间的数据。
  4. 实现其他需要跨场景的功能,如组队,聊天,帮派等。

Phys Server 主要用于玩家移动,碰撞等检测。

所有玩家的移动类操作都在该服务器上做检查,所以该服务器本身具备所有地图的地形等相关信息。具体检查过程是这样的:首先,Worldserver收到一个移动信息,WorldServer收到后向Phys Server请求检查,Phys Server检查成功后再返回给world Server,然后world server传递给相应的Scene Server。

Scene Server 场景服务器,按场景划分,每个服务器负责的场景应该是可以配置的。理想情况下是可以动态调节的。

ItemMgr Server 物品管理服务器,负责所有物品的生产过程。在该服务器上存储一个物品掉落数据库,服务器初始化的时候载入到内存。任何需要产生物品的服务器均与该服务器直接通信。

AIServer 又一个功能服务器,负责管理所有NPC的AI。AI服务器通常有2个输入,一个是Scene Server发送过来的玩家相关操作信息,另一个时钟Timer驱动,在这个设计中,对其他服务器来说,AIServer就是一个拥有很多个NPC的客户端。AIserver需要同步所有与AI相关的数据,包括很多玩家数据。由于AIServer的Timer驱动特性,可在很大程度上使用TBB程序库来发挥多核的性能。

把网络游戏服务器分拆成多个进程,分开部署。这种设计的好处是模块自然分离,可以单独设计。分担负荷,可以提高整个系统的承载能力。

缺点在于,网络环境并不那么可靠。跨进程通讯有一定的不可预知性。服务器间通讯往往难以架设调试环境,并很容易把事情搅成一团糨糊。而且正确高效的管理多连接,对程序员来说也是一项挑战。

前些年,我也曾写过好几篇与之相关的设计。这几天在思考一个问题:如果我们要做一个底层通用模块,让后续开发更为方便。到底要解决怎样的需求。这个需求应该是单一且基础的,每个应用都需要的。

正如 TCP 协议解决了互联网上稳定可靠的点对点数据流通讯一样。游戏世界实际需要的是一个稳定可靠的在游戏系统内的点对点通讯需要。

我们可以在一条 TCP 连接之上做到这一点。一旦实现,可以给游戏服务的开发带来极大的方便。

可以把游戏系统内的各项服务,包括并不限于登陆,拍卖,战斗场景,数据服务,等等独立服务看成网络上的若干终端。每个玩家也可以是一个独立终端。它们一起构成一个网络。在这个网络之上,终端之间可以进行可靠的连接和通讯。

实现可以是这样的:每个虚拟终端都在游戏虚拟网络(Game Network)上有一个唯一地址 (Game Network Address , GNA) 。这个地址可以预先设定,也可以动态分配。每个终端都可以通过游戏网络的若干接入点 ( GNAP ) 通过唯一一条 TCP 连接接入网络。接入过程需要通过鉴权。

鉴权过程依赖内部的安全机制,可以包括密码证书,或是特别的接入点区分。(例如,玩家接入网络就需要特定的接入点,这个接入点接入的终端都一定是玩家)

鉴权通过后,网络为终端分配一个固定的游戏域名。例如,玩家进入会分配到 player.12345 这样的域名,数据库接入可能分配到 database 。

游戏网络默认提供一个域名查询服务(这个服务可以通过鉴权的过程注册到网络中),让每个终端都能通过域名查询到对应的地址。

然后,游戏网络里所有合法接入的终端都可以通过其地址相互发起连接并通讯了。整个协议建立在 TCP 协议之上,工作于唯一的这个 TCP 连接上。和直接使用 TCP 连接不同。游戏网络中每个终端之间相互发起连接都是可靠的。不仅玩家可以向某个服务发起连接,反过来也是可以的。玩家之间的直接连接也是可行的(是否允许这样,取决于具体设计)。

由于每个虚拟连接都是建立在单一的 TCP 连接之上。所以减少了互连网上发起 TCP 连接的各种不可靠性。鉴权过程也是一次性唯一的。并且我们提供域名反查服务,我们的游戏服务可以清楚且安全的知道连接过来的是谁。

系统可以设计为,游戏网络上每个终端离网,域名服务将广播这条消息,通知所有人。这种广播服务在互联网上难以做到,但无论是广播还是组播,在这个虚拟游戏网络中都是可行的。

在这种设计上。在逻辑层面,我们可以让玩家直接把聊天信息从玩家客互端发送到聊天服务器,而不需要建立多余的 TCP 连接,也不需要对转发处理聊天消息做多余的处理。聊天服务器可以独立的存在于游戏网络。也可以让广播服务主动向玩家推送消息,由服务器向玩家发起连接,而不是所有连接请求都是由玩家客互端发起。

虚拟游戏网络的构成是一个独立的层次,完全可以撇开具体游戏逻辑来实现,并能够单独去按承载量考虑具体设计方案。非常利于剥离出具体游戏项目来开发并优化。

最终,我们或许需要的一套 C 库,用于游戏网络内的通讯。api 可以和 socket api 类似。额外多两条接入与离开游戏网络即可。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/444977.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode63 不同路径II

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 现在考虑网格中有障碍物。那么从左上角到右下角将…

leetcode55 跳跃游戏 秒杀所有答案

给定一个非负整数数组,你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个位置。 示例 1: 输入: [2,3,1,1,4] 输出: true 解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 …

leetcode45 跳跃游戏II 秒杀所有答案

给定一个非负整数数组,你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 你的目标是使用最少的跳跃次数到达数组的最后一个位置。 示例: 输入: [2,3,1,1,4] 输出: 2 解释: 跳到最后一个位置的最小跳跃数是 2。 从下标为 …

MachineLearning(7)-决策树基础+sklearn.DecisionTreeClassifier简单实践

sklearn.DecisionTreeClassifier决策树简单使用1.决策树算法基础2.sklearn.DecisionTreeClassifier简单实践2.1 决策树类2.3 决策树构建2.3.1全数据集拟合,决策树可视化2.3.2交叉验证实验2.3.3超参数搜索2.3.4模型保存与导入2.3.5固定随机数种子参考资料1.决策树算法…

leetcode72 编辑距离

给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作: 插入一个字符 删除一个字符 替换一个字符 示例 1: 输入: word1 "horse", word2 "ros" 输出: 3 解释: ho…

即时通讯系统架构

有过几款IM系统开发经历,目前有一款还在线上跑着。准备简单地介绍一下大型商业应用的IM系统的架构。设计这种架构比较重要的一点是低耦合,把整个系统设计成多个相互分离的子系统。我把整个系统分成下面几个部分:(1)状态…

leetcode303 区域和检索

给定一个整数数组 nums,求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和,包含 i, j 两点。 示例: 给定 nums [-2, 0, 3, -5, 2, -1],求和函数为 sumRange() sumRange(0, 2) -> 1 sumRange(2, 5) -> -1 sumRange(0,…

网络游戏的客户端同步问题 .

有关位置同步的方案实际上已经比较成熟,网上也有比较多的资料可供参考。在《带宽限制下的视觉实体属性传播》一文中,作者也简单提到了位置同步方案的构造过程,但涉及到细节的地方没有深入,这里专门针对这一主题做些回顾。 最直接的…

leetcode319 灯泡的开关

初始时有 n 个灯泡关闭。 第 1 轮,你打开所有的灯泡。 第 2 轮,每两个灯泡你关闭一次。 第 3 轮,每三个灯泡切换一次开关(如果关闭则开启,如果开启则关闭)。第 i 轮,每 i 个灯泡切换一次开关。 …

网游服务器端设计思考:心跳设计

网络游戏服务器的主要作用是模拟整个游戏世界,客户端用过网络连接把一些信息数据发给服务器,在操作合法的情况下,更新服务器上该客户端对应的player实体、所在场景等,并把这些操作及其影响广播出去。让别的客户端能显示这些操作。…

算法(25)-括号

各种括号1.LeetCode-22 括号生成--各种括号排列组合2.LeetCode-20 有效括号(是否)--堆栈3.LeetCode-32 最长有效括号(长度)--dp4.LeetCode-301删除无效括号 --多种删除方式1.LeetCode-22 括号生成–各种括号排列组合 数字 n 代表生成括号的对数,请你设计一个函数&a…

leetcode542 01矩阵

给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。 两个相邻元素间的距离为 1 。 示例 1: 输入: 0 0 0 0 1 0 0 0 0 输出: 0 0 0 0 1 0 0 0 0 示例 2: 输入: 0 0 0 0 1 0 1 1 1 输出: 0 0 0 0 1 0 1 2 1 注意: 给定矩阵的元素个数不超过 10000。…

RPC、RMI与MOM与组播 通信原理 .

远程过程调用(RPC): 即对远程站点机上的过程进行调用。当站点机A上的一个进程调用另一个站点机上的过程时,A上的调用进程挂起,B上的被调用过程执行,并将结果返回给调用进程,使调用进程继续执行【…

一个简单的游戏服务器框架 .

最近一段时间不是很忙,就写了一个自己的游戏服务器框架雏形,很多地方还不够完善,但是基本上也算是能够跑起来了。我先从上层结构说起,一直到实现细节吧,想起什么就写什么。 第一部分 服务器逻辑 服务器这边简单的分为三…

leetcode97 交错字符串

给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。 示例 1: 输入: s1 "aabcc", s2 "dbbca", s3 "aadbbcbcac" 输出: true 示例 2: 输入: s1 "aabcc", s2 "dbbca", s3 "aadbbbaccc" 输…

leetcode 33 搜索旋转排序数组 到处是细节的好题

这个题想了想就会做,只是细节真的能卡死人,找了好久的bug。甚至我怀疑我现在的代码可能还有错,只是没例子测出来。 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1…

MachineLearning(8)-PCA,LDA基础+sklearn 简单实践

PCA,LDA基础sklearn 简单实践1.PCAsklearn.decomposition.PCA1.PCA理论基础2.sklearn.decomposition.PCA简单实践2.LDAsklearn.discriminant_analysis.LinearDiscriminantAnalysis2.1 LDA理论基础2.2 sklearn LDA简单实践1.PCAsklearn.decomposition.PCA 1.PCA理论基础 PCA:&…

leetcode198 打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的…

linux下的RPC

一、概述 在传统的编程概念中,过程是由程序员在本地编译完成,并只能局限在本地运行的一段代码,也即其主程序和过程之间的运行关系是本地调用关系。因此这种结构在网络日益发展的今天已无法适应实际需求。总而言之,传统过程调用模式…

算法(28)--矩阵搜索系列

矩阵搜索1.leetcode-200. 岛屿数量2.leetcode-695. 岛屿的最大面积3.leetcode-463. 岛屿的周长4.剑指 Offer 12. 矩阵中的路径5.leetcode-329. 矩阵中的最长递增路径6.leetcode-1091. 二进制矩阵中的最短路径1.leetcode-200. 岛屿数量 给你一个由 ‘1’(陆地&#…