Skip to content

用Unity做个游戏(九) – 服务端架构

前言

最近一直在思考某些事情,然后就拖更了一个月233
其实代码也一直在写,游戏的主流程也基本上通了,就是一直懒得写博客。
OK我们今天来介绍下游戏的服务端是怎么实现的。

服务端结构

BounceArena的服务端使用node.js开发,这次用了三个进程,分别处理日志(main.js也是程序入口),socket通信(SFSocketHandler.js)和具体的业务逻辑(SFGameServer.js)。

main.js

main.js为程序入口,我们在server/app目录下执行node ./指令就可以了。
这个进程会启动两个子进程SFSocketHandler.jsSFGameServer.js,这两个进程运行过程中产生的日志会通过node的进程通信机制发送给main.js,然后主进程统一处理这些信息,比如格式化输出,另存到文件等等。
主要代码如下:

其中onExit()后面会详细说明,然后log()是用于输出日志的方法(其实也可以用log4js之类的库,我当时不知道有这个东西,写完了才发现有个现成的库可以用orz)
不过既然写了,就姑且贴出来吧233

这里使用了color库来方便地设置文本的颜色

我们想结束程序的时候,会按下ctrl+c组合键,为了使所有进程全部正常安全地退出,我这里监听了SIGINT中断事件,当主进程接收到该信号时,不会立即退出,而是等待子进程全部安全正常地结束之后才会退出

main.js的主要内容就是这些了

SFSocketHandler.js

主进程会执行这个文件作为一个子进程
这个进程负责的事情是开启TCP服务器,承载TCP连接,接收来自于客户端的原始数据并作出第一步的处理,然后把整理过的数据发送给SFGameServer来处理具体的业务逻辑
主要代码如下:

进程通信使用redis的订阅机制,经过测试,node自带的process.send()不好用,延迟非常高,用redis的订阅的话,延迟可以大幅降低,所以就采用redis来做进程通信了
然后就是onSocket这个主要的方法了:

经过之前踩过的坑,socket在接收数据时,由于网络拥堵等原因可能会发生粘包或者断包,这时就要自己处理分包逻辑。这里约定数据包的格式为JSON字符串+\r\n\r\n四个字符,以此来划分粘连在一起的数据包。大致逻辑如下:

GameServer处理完请求数据后,必定会发送一个相应返回给客户端,同样的,Response信息将会由GameServer先发送给SocketHandler,然后由后者发送给相应的socket连接

给客户端发送数据时,如果网络连接不畅而且发送的数据量特别大,可能会导致系统的发送缓冲区溢出,导致客户端不能收到全部的信息,就不妙了。
还好node的socket在发送方法socket.write()提供了一个返回值,如果返回false的话则说明缓冲区已经开始紧张了,此时如果再有数据需要发送则可能会出问题,所以我们就先把接下来需要发送的数据全部暂存在writeBuffer中,直到收到drain事件,说明缓冲区已清空, 我们就可以继续发送数据了

SFGameServer.js

主进程会执行这个文件作为另外一个子进程
这个进程负责处理具体的业务逻辑。大致的思路是根据协议号pid来选择合适的Controller来处理逻辑,初始化过程如下:

然后根据从SocketHandler收到的请求数据,选择相应的Controller。

当然还要准备推送Response给客户端的方法pushMessage

之后就是具体各个Controller的实现了,具体逻辑我们下次再说
需要注意的是,每个Controller都要提供setPuhser()方法用来设置推送方法,以及onRequest()方法用来处理请求信息

完整代码

上面贴出的代码片段由于篇幅限制只保留了关键部分,完整的代码可在我的github上找到

有用! (0)
Published inBounceArena

2 Comments

  1. darker darker

    兄弟真是给力啊,刚转unity3d,看到你这系列的博客真的是获益匪浅啊,为什么不接着写了,如果可能的话能不能加个QQ微信什么的交流一下呢~~~

    • inspoy inspoy

      最近一直在忙其他的事情orz
      这个项目算是就这样告一段落了,之后有空了再把这个系列完结掉233

发表评论

电子邮件地址不会被公开。 必填项已用*标注