3DMMO游戏服务器架构
服务器框架
备选资源
网络通信协议的选择
-
结论:由于客户端最后选择了UNITY3D引擎,所以有些选择考虑到客户端的实现做了妥协。最后选择了libuv+byteStream,并且自己做了一层封装,起名为UVSocket。代码我提交到了oschina。 代码库:UVSocket
-
原因:
- 首先,如果不考虑客户端,我的首选会是RakNet,毕竟是老牌的游戏通信库,而且UDP从延迟角度来说也更适合用于网络游戏。并且收发包没有分包合包的烦恼。但是RakNet并没有官方的C#实现,因此客户端担心和UNITY3D结合使用过程中会遇到各个平台的兼容性问题,最后放弃了RakNet。ENet也有类似的问题,而且ENet本身还有连接数量限制,所以直接就放弃了。libuv因为是原生的BSDSocket封装,并且我之前在做账服的时候也用过,稳定性和性能都很不错,因此最终还是选择了libuv。
- 至于消息协议,我们也争论了很久,主要分歧在于ProtoBuf和ByteStream(过程中还考虑了Flatbuffer,但是出于易用性和编码习惯考虑,排除了)。
- ProtoBuf的优势在于消息解析自动化模板化,无需程序员关心,并且兼容性好,增加字段不会影响旧版本。接口封装优秀,使用起来代码较清晰,同时有对数据进行压缩,能够节省一定的流量。缺点则是性能开销较ByteStream高,需要生成的文件多,proto文件编译较慢。然而最重要的缺点也恰恰是它的优点,就是模板化。游戏业务繁杂,每个消息长的都不一样,如果用通用消息,就失去了模板化的意义,如果用模板,那么每个消息都得定义一个模板。根据之前游戏的开发情况来看,消息量成百上千,那么最后工程将会多出两倍消息量的文件数量,这对编译速度的影响是非常恐怖的,同时也增加了游戏业务开发的工作量。
- ByteStream的优点是速度快,效率高,并且由于没有固定的消息格式,对于游戏业务千奇百怪的消息格式也能灵活应对。缺点则是容易出错,向后兼容性差。
- 经过权衡,我们还是决定使用ByteStream。但是又对ByteStream进行了优化。对于整数类型(signed/unsigned char/short/int/long long等),根据数值大小自动决定采用不同的长度。增加了一个table类型,用于发送结构化数据,并且能够支持扩充字段。(详情可以参看UVSocket里的CByteStream类)。
关于登录步骤的思考
- 登录分成多个步骤,真的有必要吗?
- 这点我觉得应该还是有的。一时间大量的数据丢给客户端,一方面大量的数据计算和发送消息,可能造成服务端的响应变慢,影响其他玩家的游戏体验。另一方面,客户端接收消息也可能造成卡顿,所以还是应该分成多个步骤来发。
- 那么分成多少个步骤合适呢?
- 这个还是要考虑到数据总量来合理分步。必不可少的应该有:
- 玩家的角色信息(名字,等级,经验值,外形等等),玩家身上的装备,称号,快捷键,军团名称和职位等玩家可以在主界面上看到的所有信息。然后将玩家切进地图。这里外形可以考虑玩家每次下线的时候将外形保存成字符串的形式存下来,这样就可以不用读取玩家的装备直接显示外形。
- 游戏过程中频繁需要使用到的基础系统相关:物品、背包、伙伴、军团、好友等。
- 其他系统可以完全通过查询的方式来实现,而不在登录时下发。