半年前我参与了一个手游项目,第一次能够主导整个游戏的设计,这篇文章单说服务器的架构,客户端就不提了。


对于服务端,我想从之前的端游服务器改过来肯定是走不通的(详见:),因为手游的开发周期比端游短很多,上面那一套架构开发了5年不止,当然,期间推翻重做了很多次。而这个手游项目只有快则6个月,慢则10个月的时间。


既然决定不用端游的架构,一切从0开始,那么快速搭建起一个可用的服务器是我考虑的第一个原则,第二点就是我做为程序员的一点私心,尽量使用以前没有用过的技术,这样自己能够接触更广阔的世界。

首先当然需要找找看有没有现成的轮子,我花了1个月的时间,去寻找github上那些不错的开源架构,其中有两套系统我觉得很有潜力,一套是网易的pomelo,另一套是云风的skynet。其实我首先知道的是skynet,因为一直关注云风的博客,所以他的这个服务端我还是有所了解的,我花了一周的时间详细阅读了skynet的wiki,并上手安装了skynet,又写了几个简单的http通信的例子,然后仔细分析了一下skynet中c模块的写法,甚至连如果要使用skynet,我的后台部署图会是什么样的都画好了,不过最后还是放弃了skynet,理由是当时已经确定了前端会用cocos2dx+lua的组合来写,我很想尝试看看,客户端和服务端的脚本语言不同会是个什么样子,同时,我还觉得,云风用c的消息队列,我还吃不透,而且当时skynet的用户还不多,没有先驱可以参照,skynet本身也还没有稳定下来,云风是个精力旺盛的家伙,更新速度太快了。现在skynet已经发布了1.0了,下个游戏很有可能我会用它。


然后我发现了node.js,其实也不能说是我发现的,公司有前辈已经开始用node.js做游戏了,我当时比较好奇,于是看了一下nodejs的网站,又看了下网上的言论,觉得这货很神奇,单线程的事件驱动,感觉比较简单。接着pomelo就进入了视野,我居然发现网易开源了一个nodejs写的游戏服务器架构,真是喜从天降,我花了2周时间搭建,学习,测试pomelo的各种使用方法,用它copy了一个网上的聊天室代码,期间遇到很多问题,我提的issue基本上没有人问津,加入pomelo开发的qq群开发者也是寥寥无几,而且网易的人问题回馈的速度让人哭,并是一副高高在上,对问题不做任何解释的姿态出现的。我修改了几个pomelo的问题后就放弃了它。但是不得不说,pomelo对我后面自己设计基于nodejs的服务器架构帮助很大,我有很大一部分设计是参考了它的想法,也是它引我进入了nodejs的世界。


在我花了将近1个月的时间,却什么都没有收获的时候,我决定找人聊一聊,我请教了很多前辈和厉害的朋友,他们给出了很多建议和帮助,也渐渐帮我理清了我到底需要做什么。但一开始写代码,我就紧张。我不想走弯路,想要一开始就走在正确的道路上,我害怕走了很远,结果发现是错的,写任何一行代码,我都压力倍增。那段时间,我痛苦,纠结,压力极大,咬手指,我压力一大就弯曲右手食指,然后用牙咬食指的第二和第三个关节,夜不能寐。终于有一天,我的好朋友XY说了一句话,让我幡然醒悟,他说“先开始写的,后面再慢慢改,哪有一开始就设计好的系统”。这么简单的一个道理,我听过无数次,却从来没有领悟是什么意思,这次真的被震动到了,确实,我想要一开始就走在正确的路上的做法明显太天真了,而我更没有必要为走错而懊恼,举步维艰,是因为我看得不够远。


于是,我开始动手了。


之前我倒是用过js,不过仅限于用 js 和 html 配合来制作网页,这次拿来写服务器,我是一点把握也没有,首先从语言开始学起,我在网上看了很久的资料,最后买了2本书,一本是 crockford 的《javascript语言精粹》,另一本是朴灵的《深入浅出nodejs》,前一本是 js 中服务器要用到的那部分,js 语言其实有三部分组成,dom + bom + 基本核心,dom是操纵页面元素的,bom 是操纵浏览器的,基本核心是语言的最基础的部分,而服务器正好只需要这部分,crockford 的书写的非常不错,我很快就看懂了,然后我花了几天时间整理了一份文档,专门讲解 js 语言的基本核心部分,用它来给我的另一个程序员朋友讲,他从来没有用过 js,我的目标是想把他讲懂,那么我肯定就理解透彻了,不过好像最后他也不太懂。。。


接着是 nodejs 的部分,朴灵大神写的书的确不错,应该是我看到的讲解 nodejs 的书里最优秀的那一类,按照他的书和nodejs官网的api文档,我开始写我的服务器了,按照我朋友的提醒,我首先写一个单进程的服务器,而服务器最主要的部分就是网络了,所以我先用 nodejs 的 net.socket 写了一个tcp的服务器,这只用十几行代码,nodejs 的 api 设计的非常不错,而且文档写的也很好,很快就理解了,而且我给 nodejs 提的 issue 很快就会得到回复,这期间我还发现 nodejs 对于 tpc,不过当时发现 nodejs 分家了还是小小担心了一下的,不过现在又合并了:)


一开始,我打算模仿 pomelo 的架构,把它的那些我不需要的东西剔除出去,不过后来我放弃了,这件事情并不那么容易,我还是老老实实从一个简单的通信开始写起,一开始我就想走多进程的路子,而且我认为这也是必须的(但是现在我不这么认为了),但是一开始并不那么好写,步子迈的大了,容易扯到蛋。XY又提醒我,还是从单进程开始设计比较好,我接受了他的意见,在这个 tcp 服务器的基础上慢慢的增加我认为游戏所必须的内容,例如数据库接口、协议、网络。基本上数据库+网络+协议就是一个完整的服务器了,其他的游戏逻辑都是可以后来慢慢铺的,正好这个时候客户端的开发也开始了,我就用 luasocket 写了一个简单的客户端网络库,拿来和我的这个单进程的服务器进行通信,终于,我的服务器跑起来了,代码很少,我控制的住,我感觉非常开心:https://github.com/rangercyh/nodejs_server


这个服务器只具备最基本的能力,和数据库能够通信,使用 tcp 和客户端进行通信,协议也是用的我自己设计的协议在通信,这里不得不说一下,一开始我是打算用 protobuf 协议来通信的,后来放弃了,因为我发现 protobuf 的 nodejs 绑定的库接口设计的非常繁复,很难用。而且我没有那么高的需求,于是就自己实现协议了,后来我才发现,其实我完全可以用 json 格式就好,不过 lua 这边处理 json 还有各种问题,这个后面我也会提到,这也是我之前说过,想尝试一下客户端和服务端使用不同语言的第一个代价。协议的解析要写两套,而且保证不出问题还是很困难的。


下一篇我会介绍一个很神奇的轮子:)