2012年5月25日

摘要: 在浅(1)中,关于游戏世界管理模块和通讯模块我没有详细说明,本篇中将补充介绍。游戏世界管理模块: 本模块专门管理游戏世界里的数据模型,也就意味着,所有游戏里的对象基本上都由他来管理所以,此模块极为复杂,甚至在大型系统里,也可以把它再划分成很多子模块来协同工作。 这个模块该怎么封装呢?首先,自然是需要一个消息处理类,因为游戏世界管理模块同样是需要消息驱动的,此模块每收到一个消息后,就察看消息类型,看是转发类型还是管理类型的消息,如果是转发类型,就将消息转发给消息目的地模块,如果是管理类型的消息,就察看管理的目标以及管理的方法,然后执行管理方法。因此,我们还需要的就是一个辨别消息的方法,以及一.. 阅读全文
posted @ 2012-05-25 18:27 很多不懂呀。。 阅读(453) 评论(0) 推荐(0) 编辑
摘要: 本游戏服务器端操作系统采用UNIX,因为UNIX是标准的服务器操作系统,可保证网络游戏的稳定性。因此,以下所有的编程都将针对UNIX进行。 服务器端的整体构架如下:通讯模块,消息传递模块,游戏规则模块,线程管理模块,游戏世界管理模块。 通讯模块: 通讯模块主要实现与客户端的通讯功能,实际上,通讯模块就是对套结字Socket的封装。Socket是UNIX下的网络通讯基础,对于一个Socket我们可以对其进行读写操作,读入的数据来自客户端,写入的数据可供客户端读取。 Socket主要有阻塞套接字和无阻塞套接字两种,对于无阻塞套结字,每次读写后,不管读写的字节数是否达到要求,都立即返回;而对于... 阅读全文
posted @ 2012-05-25 18:26 很多不懂呀。。 阅读(556) 评论(0) 推荐(0) 编辑
摘要: MMORPG不同于其它的局域网的网络游戏,它是一个面向整个Internet的连接人数过万的网络游戏,因此他的服务器端设计则极为重要服务器的基本设置 在大型网络游戏里,通常设计为C/S结构,客户端不再对数据进行逻辑处理,而只是一个收发装置,从玩家那里接受到操作信息,然后反馈给服务器,再由服务器进行处理后发回客户端,经客户端通过图形化处理,给玩家呈现出一个缤纷的游戏世界。登陆服务器 在这里也可以称之为连接服务器,网络游戏的客户端一般是连接到这里,然后再由该连接服务器根据不同的需要,把游戏消息转发给其它相应的服务器(逻辑和地图服务器)也因为它是客户端直接连接的对象,它同时也负担了验证客户身份的工.. 阅读全文
posted @ 2012-05-25 18:24 很多不懂呀。。 阅读(568) 评论(0) 推荐(0) 编辑
摘要: 狭义的游戏对象是指游戏世界中所能看到及可交互的对象,如玩家、怪物、物品等,我们这里也主要讨论这类对象在服务器上的组织及实现。 在大部分的MMOG中,游戏对象的类型都大同小异,主要有物品、生物、玩家等。比如在wow中,通过服务器发下来的GUID我们可以了解到,游戏中有9大类对象,包括物品(Item)、背包(Container)、生物(Unit)、玩家(Player)、游戏对象(GameObject)、动态对象(DynamicObject)、尸体(Corpse)等。 在mangos的实现中,对象使用类继承的方式,由Object基类定义游戏对象的公有接口及属性,包括GUID的生成及管理、构造及更.. 阅读全文
posted @ 2012-05-25 18:15 很多不懂呀。。 阅读(870) 评论(0) 推荐(0) 编辑
摘要: 关于登录服、大区服及游戏世界服的结构之前已做过探讨,这里再把各自的职责和关系列一下。 GateWay/WorldServer GateWay/WodlServer LoginServer LoginServer DNSServer WorldServerMgr | | | | | --------------------------------------------------------------------------------------------- | | | internet | clients其中DNSServer负责带负载均衡的域名解析服务,返回LoginServer的I 阅读全文
posted @ 2012-05-25 18:14 很多不懂呀。。 阅读(749) 评论(0) 推荐(0) 编辑
摘要: 其中game工程生成的库文件game.lib居然有近四百兆之巨,mangosd和realmd在连接这个库的时候也要花上好长一段时间。当然,mangos现在的代码量也确实不少了,这也就要考虑到大的工程项目的源代码管理及模块工程划分,至少,像mangos现在这样,代码全部放入game目录中,并且就做为一个大的工程的方式,其弊端是已经显现了。另外还有功能模块划分的问题,需要找一个功能的实现时,不知道该到哪块代码去找,而要扩展某部分功能时,也是无从下手。 模块划分使用最广泛也是最容易实现的应该算是按接口编程了,实现的方法不用我多说,程序员都知道。其好处也是显而易见的,定义了接口之后,接口的实现便可以. 阅读全文
posted @ 2012-05-25 18:14 很多不懂呀。。 阅读(319) 评论(0) 推荐(0) 编辑
摘要: 有关State模式的设计意图及实现就不从设计模式中摘抄了,我们只来看看游戏服务器编程中如何使用State设计模式。 首先还是从mangos的代码开始看起,我们注意到登录服在处理客户端发来的消息时用到了这样一个结构体: struct AuthHandler { eAuthCmd cmd; uint32 status; bool (AuthSocket::*handler)(void); }; 该结构体定义了每个消息码的处理函数及需要的状态标识,只有当前状态满足要求时才会调用指定的处理函数,否则这个消息码的出现是不合法的。这个status状态标识的定义是一个宏,有两种有... 阅读全文
posted @ 2012-05-25 18:13 很多不懂呀。。 阅读(477) 评论(0) 推荐(0) 编辑
摘要: 有些类似于QT中的event与signal,我将一些动作请求消息定义为事件,而将状态改变消息定义为信号。比如在QT应用程序中,用户的一次鼠标点击会产生一个鼠标点击事件加入到事件队列中,当处理此事件时可能会导致某个按钮控件产生一个clicked()信号。对应到我们的服务器上的一个例子,玩家登录时会发给服务器一个请求登录的数据包,服务器可将其当作一个用户登录事件,该事件处理完后可能会产生一个用户已登录信号。这样,与QT类似,对于事件我们可以重定义其处理方法,甚至过滤掉某些事件使其不被处理,但对于信号我们只是收到了一个通知,有些类似于Observe模式中的观察者,当收到更新通知时,我们只能更新自己的 阅读全文
posted @ 2012-05-25 18:13 很多不懂呀。。 阅读(339) 评论(0) 推荐(0) 编辑
摘要: 前面一直都在说接收数据时的处理方法,我们应该用专门的IO线程,接收到完整的消息包后加入到主线程的消息队列,但是主线程如何发送数据还没有探讨过。 一般来说最直接的方法就是逻辑线程什么时候想发数据了就直接调用相关的socket API发送,这要求服务器的玩家对象中保存其连接的socket句柄。但是直接send调用有时候有会存在一些问题,比如遇到系统的发送缓冲区满而阻塞住的情况,或者只发送了一部分数据的情况也时有发生。我们可以将要发送的数据先缓存一下,这样遇到未发送完的,在逻辑线程的下一次处理时可以接着再发送。 考虑数据缓存的话,那这里这可以有两种实现方式了,一是为每个玩家准备一个缓冲区,另外就.. 阅读全文
posted @ 2012-05-25 18:12 很多不懂呀。。 阅读(522) 评论(0) 推荐(0) 编辑
摘要: 当阅读一项工程的源码时,我们大概会选择从main函数开始,而当开始一项新的工程时,第一个写下的函数大多也是main。那我们就先来看看,游戏服务器代码实现中,main函数都做了些什么。 由于我在读技术文章时最不喜看到的就是大段大段的代码,特别是那些直接Ctrl+C再Ctrl+V后未做任何修改的代码,用句时髦的话说,一点技术含量都没有!所以在我们今后所要讨论的内容中,尽量会避免出现直接的代码,在有些地方确实需要代码来表述时,也将会选择使用伪码。 先从mangos的登录服代码开始。mangos的登录服是一个单线程的结构,虽然在数据库连接中可以开启一个独立的线程,但这个线程也只是对无返回结果的执... 阅读全文
posted @ 2012-05-25 18:11 很多不懂呀。。 阅读(952) 评论(0) 推荐(0) 编辑
摘要: 既然说到了消息队列,那我们继续来稍微多聊一点吧。 我们所能想到的最简单的消息队列可能就是使用stl的list来实现了,即消息队列内部维护一个list和一个互斥锁,putMessage时将message加入到队列尾,getMessage时从队列头取一个message返回,同时在getMessage和putMessage之前都要求先获取锁资源。 实现虽然简单,但功能是绝对满足需求的,只是性能上可能稍稍有些不尽如人意。其最大的问题在频繁的锁竞争上。 对于如何减少锁竞争次数的优化方案,Ghost Cheng提出了一种。提供一个队列容器,里面有多个队列,每个队列都可固定存放一定数量的消息。网络IO... 阅读全文
posted @ 2012-05-25 18:11 很多不懂呀。。 阅读(518) 评论(0) 推荐(0) 编辑
摘要: 消息队列锁调用太频繁的问题算是解决了,另一个让人有些苦恼的大概是这太多的内存分配和释放操作了。频繁的内存分配不但增加了系统开销,更使得内存碎片不断增多,非常不利于我们的服务器长期稳定运行。也许我们可以使用内存池,比如SGI STL中附带的小内存分配器。但是对于这种按照严格的先进先出顺序处理的,块大小并不算小的,而且块大小也并不统一的内存分配情况来说,更多使用的是一种叫做环形缓冲区的方案,mangos的网络代码中也有这么一个东西,其原理也是比较简单的。 就好比两个人围着一张圆形的桌子在追逐,跑的人被网络IO线程所控制,当写入数据时,这个人就往前跑;追的人就是逻辑线程,会一直往前追直到追上跑的人. 阅读全文
posted @ 2012-05-25 18:11 很多不懂呀。。 阅读(341) 评论(0) 推荐(0) 编辑
摘要: 正如我们在前面曾讨论过的,登录服要实现的功能相当简单,就是帐号验证。为了便于描述,我们暂不引入那些讨论过的优化手段,先以最简单的方式实现,另外也将基本以mangos的代码作为参考来进行描述。 想象一下帐号验证的实现方法,最容易的那就是把用户输入的明文用帐号和密码直接发给登录服务器,服务器根据帐号从数据库中取出密码,与用户输入的密码相比较。 这个方法存在的安全隐患实在太大,明文的密码传输太容易被截获了。那我们试着在传输之前先加一下密,为了服务器能进行密码比较,我们应该采用一个可逆的加密算法,在服务器端把这个加密后的字串还原为原始的明文密码,然后与数据库密码进行比较。既然是一个可逆的过程,那... 阅读全文
posted @ 2012-05-25 18:10 很多不懂呀。。 阅读(605) 评论(0) 推荐(0) 编辑
摘要: 都已经看出来了,这种每切换一次地图就要重新连接服务器的方式实在是不够优雅,而且在实际游戏运营中也发现,地图切换导致的卡号,复制装备等问题非常多,这里完全就是一个事故多发地段,如何避免这种频繁的连接操作呢? 最直接的方法就是把那个图倒转过来就行了。客户端只需要连接到中心服上,所有到地图服务器的数据都由中心服来转发。很完美的解决方案,不是吗? 这种结构在实际的部署中也遇到了一些挑战。对于一般的MMORPG服务器来说,单台服务器的承载量平均在2000左右,如果你的服务器很不幸地只能带1000人,没关系,不少游戏都是如此;如果你的服务器上跑了3000多玩家依然比较流畅,那你可以自豪地告诉你的策划... 阅读全文
posted @ 2012-05-25 18:09 很多不懂呀。。 阅读(852) 评论(1) 推荐(0) 编辑
摘要: 如果我们就此打住,可能马上就会有人要嗤之以鼻了,就这点古董级的技术也敢出来现。好吧,我们还是把之前留下的问题拿出来解决掉吧。 一般来说,当某一部分能力达不到我们的要求时,最简单的解决方法就是在此多投入一点资源。既然想要更多的连接数,那就再加一台网关服务器吧。新增加了网 关服后需要在大区服上做相应的支持,或者再简单点,有一台主要的网关服,当其负载较高时,主动将新到达的连接重定向到其他网关服上。 而对于游戏服来说,有一台还是多台网关服是没有什么区别的。每个代表客户端玩家的对象内部都保留一个代表其连接的对象,消息广播时要求每个玩家对象使用自 己的连接对象发送数据即可,至于连接是在什么地方,那... 阅读全文
posted @ 2012-05-25 18:09 很多不懂呀。。 阅读(571) 评论(0) 推荐(0) 编辑
摘要: 回想一下我们在玩wow时的操作流程:运行wow.exe进入游戏后,首先就会要求我们输入用户名和密码进行验证,验证成功后才会出来游戏世界列表,之后是排队进入游戏世界,开始游戏... 可以看到跟前面的描述有个很明显的不同,那就是要先验证帐号再选择游戏世界。这种结构也就使得登录服不是固定配备给个游戏世界,而是全区共有的。 我们可以试着从实际需求的角度来考虑一下这个问题。正如我们之前所描述过的那样,登录服在大多数情况下都是比较空闲的,也许我们的一个拥有20个游戏世界的大区仅仅使用10台或更少的登录服即可满足需求。而当在开新区的时候,或许要配备40台登录服才能应付那如潮水般涌入的玩家登录请求。所... 阅读全文
posted @ 2012-05-25 18:08 很多不懂呀。。 阅读(587) 评论(1) 推荐(0) 编辑
摘要: 讨论了这么久我们一直都还没有进入游戏世界服务器内部,现在就让我们来窥探一下里面的结构吧。 对于现在大多数MMORPG来说,游戏服务器要处理的基本逻辑有移动、聊天、技能、物品、任务和生物等,另外还有地图管理与消息广播来对其他高级功能做支撑。如纵队、好友、公会、战场和副本等,这些都是通过基本逻辑功能组合或扩展而成。 在所有这些基础逻辑中,与我们要讨论的服务器结构关系最紧密的当属地图管理方式。决定了地图的管理方式也就决定了我们的服务器结构,我们仍然先从最简单的实现方式开始说起。 回想一下我们曾战斗过无数个夜晚的暗黑破坏神,整个暗黑的世界被分为了若干个独立的小地图,当我们在地图间穿越时,一般都要... 阅读全文
posted @ 2012-05-25 18:08 很多不懂呀。。 阅读(489) 评论(0) 推荐(0) 编辑
摘要: 好的结构不是一蹴而就的,而且每个设计者心中的那把尺都不相同,所以这个优秀结构的定义也就没有定论。在这里,我们不打算对现有游戏结构做评价,而是试着从头开始搭建一个我们需要的MMOG结构。 对于一个最简单的游戏服务器来说,它只需要能够接受来自客户端的连接请求,然后处理客户端在游戏世界中的移动及交互,也即游戏逻辑处理即可。如果我们把这两项功能集成到一个服务进程中,则最终的结构很简单: client ----- server 嗯,太简单了点,这样也敢叫服务器结构?好吧,现在我们来往里面稍稍加点东西,让它看起来更像是服务器结构一些。 一般来说,我们在接入游戏服务器的时候都会要提供一个帐号和密码... 阅读全文
posted @ 2012-05-25 18:07 很多不懂呀。。 阅读(911) 评论(0) 推荐(0) 编辑
摘要: 关于服务器中玩家数据缓存: 服务器在启动的时候会从数据库中导入大量的信息,包括玩家的基本信息,玩家的活动信息,邮件,好友,组队等等。 问题:哪些信息是必须在服务器初始化时导入的? 考虑这个问题的因素:并不是所有的玩家角色活动频繁,有一部分的玩家长时间是不登陆的,全部导入会增加服务器的内存,而且查询服务器数据也会带来效率的影响。 考虑的方案:服务器启动初始化时,仅仅从数据库获取一些经常需要用到的数据,如玩家角色信息,其他数据在需要用到时动态的添加到服务器缓存中。账号服务器也可以采取这样的方案,单个账号服务器存放大量的玩家账号数据,账号服务器启动时候,不导入任何数据,当玩家第一次登陆时候,从数据库 阅读全文
posted @ 2012-05-25 18:03 很多不懂呀。。 阅读(406) 评论(0) 推荐(0) 编辑
摘要: 要在游戏开发最初清楚地知道需要做些什么,就必须构造程序的操作流,并确保能够很容易地对程序进行修改。一个典型的程序,首先要初始化所有的系统和数据,然后进入主循环,大部分事情都出现在主循环中,根据游戏状态(标题画面,菜单画面,游戏画面等),需要对输入和输出进行不同的处理。 下面是一个标准游戏应用程序应该遵循的步骤:1、初始化系统(Windows,图形,输入等)。2、准备数据(加载配置文件)。3、配置缺省状态(一般是标题画面)。 4、开始主循环。5、判定状态并通过获取输入、输出并对之进行处理。6、如果应用程序没结束,则返回第5步,否则进行第7步。7、清除数据(释放内存资源等)。8、释放系统(Wind 阅读全文
posted @ 2012-05-25 17:57 很多不懂呀。。 阅读(361) 评论(0) 推荐(0) 编辑

导航