基于Select多路复用的游戏服务端框架研究与实现
2020-09-24章国雁
章国雁
(安徽工商职业学院 信息工程学院,安徽 合肥230001)
一、引 言
网络游戏(Online Game)是指由软件程序和信息数据构成,通常以客户端、网页浏览器和包括移动电话、联网游戏机等各类信息设备的其他移动终端为载体,以游戏运营商服务器为处理器,以互联网为数据传输媒介的游戏产品及服务[1]。网络游戏依据载体的不同,包括基于普通PC 机的端游、基于浏览器运行的页游、基于XBOX、PS4等的主机游戏、基于手机/iPad等移动设备的手游。其中,端游由于运行在PC 机平台上,该种类游戏一般制作较为精良,画面效果较好,受众玩家对游戏的要求也更高一些;页游主要运行在浏览器上,直接打开即可运行游戏,该种类游戏往往画面效果较为一般,但由于不用下载游戏文件,打开网页可直接开始玩,较为便捷,受众群体多为对游戏画面和玩法要求不高的玩家;主机游戏的画面效果最好,制作最为精良,但要求有配套的主机设备,游戏操作对玩家的专业性要求也更高;手游受益于近些年手机和iPad等移动端用户的大量增加,该种类游戏玩法和画面效果好于页游,较好地利用了用户的空余间隔,玩法较为简便,是目前为止发展较好的类别。
二、服务端关键技术
1.网络协议
网络协议是保障网络游戏基本通信的前提,合理地选择网络协议将使游戏更加高效、稳定和安全[2]。传输控制协议(TCP)和用户数据报协议(UDP)是网络游戏研发中常用的两个协议。
传输控制协议作为一种面向有连接的协议,位于传输层,服务可靠性非常高,为了便于传输,将大块的数据包以报文段为单位进行分割,方便数据管理。传输控制协议之所以拥有可靠性,是该协议能够把数据无误地传到对方,针对丢包可以进行重发,对次序错误的数据包进行顺序调整;还具有控制通信流量的功能,发送数据前先确认通信对方是否存在,不存在不会发送数据。通常传输控制协议连接会有三次“握手”建立,断开连接要经过四次。
用户数据报协议是无连接、不可靠的协议,发送数据前不确认通信对方是否存在,直接把数据发送到网络中,因此并不能确认该数据是否到达终端节点,也不能确认数据到达的顺序是否正确。
2.Socket(套接字)
Socket(套接字)由端口号拼接IP 地址构成,它是传输层实现端到端通信的一个端点,每一次连接都有两个端点,套接字表示形式为主机IP 地址:主机16位端口号。假设一个IP地址为202.57.134.29,端口号为85 的主机,那么其套接字形式为(202.57.134.29:85)。
3.I/O模型
Select 模式是 Winsock 中最常见的 I/O 模型[3]。它主要是使用select 函数来实现对I/O的管理,并判断套接字上是否能写入或者存在数据[4]。当系统内核检测到进程的1个或者多个I/O条件准备完毕时,Select 多路复用模式会通知该进程。该模型的优点在于减少了系统开销,系统不必频繁创建和维护大量的进程或者线程。
4.分布式数据库
现在网络游戏功能复杂,玩家需要存储大量的数据,除了基本的用户账号、密码等信息外,还有游戏角色相关的大量数据需要在数据库中长期保存。由于网络游戏对画面传输的同步性要求较高,如果数据库采用同步的模式,网络延迟较大。可以使用分布式数据库,采用异步的方式对数据库进行操作。
三、通用服务端框架设计
游戏服务端主要任务是接收和处理游戏客户端发送过来的大量信息,以及存储和读取玩家账号角色相关的数据,依据这一任务内涵,一款通用的小型网络游戏服务端框架可以按图1 方式实现,采用Select 多路复用服务端架构,“网络底层”模块位于架构的底层,主要功能为处理数据粘包半包、协议解析等,主要代码封装在NetManager 类中进行实现;“消息处理”模块属于架构的逻辑层,如客户端向服务端发送“移动”协议时,服务端在该模块中记录玩家的位置信息,然后把“移动”协议广播给所有在线的客户端,其他客户端收到信息后根据最新的数据更新其对应玩家的位置;“事件处理”模块主要处理玩家的上线和下线操作,玩家新上线时,首先需要读取数据库中保存的数据,然后初始化角色信息,当玩家下线时,需要保存玩家的最新数据到数据库中等。“数据库底层”模块包含游戏数据的新增、读取、修改、删除等功能,例如账户登录时密码的校验、新玩家注册时账户名的重复性检测、玩家数据(如等级)的读取等,是服务端和数据库本身数据通信的中介。“存储处理”模块主要是区分数据的存储形式,游戏中有些数据,如玩家等级、金币、装备、经验值等需要长期保存,有些则可以临时保存。
该框架在网络带宽较好地情况下,可承载1 万名左右玩家同时在线游戏,可保持较好的游戏体验。该服务端框架采用TCP 协议进行通信,使用Json 进行通信编码,使用MySQL 数据库保存玩家数据。
图1 服务端框架
四、通用服务端框架实现
服务端程序具有粘包半包处理、协议解析、心跳机制、数据库存储等功能。
1.网络管理器NetManager功能
服务端框架中“网络底层”模块的核心部分主要实现创建监听套接字listenSocket、管理客户端状态列表checkReadList、绑定、开启端口监听(服务器启动成功)、Select 多路复用检测可读对象、新客户端连接处理ReadListenSocket、客户端消息处理ReadCliendfd、定时器等功能,服务端进入StartServerLoop循环状态,其核心代码如下:
2.协议解析
采用Json 编码解码,其格式简介、层次结构清晰,不但便于人去阅读和编写,也便于机器去解析和生成,采用Json 编码的方式可以提升网络数据的传输效率。
.net 内置了编码解码Json 的方法“JavaScriptJ-sonSerializer”,需要手动引用System.web.Extensions命名空间。Json编码解码的代码如下:
3.心跳机制
如果客户端掉线或者信号不好导致网络断开,服务端应该能及时发现并释放资源,对单个客户端来说,资源的释放作用不是很明显,因为单个客户端只有一个Socket 占用资源,而对服务端来说却是连接着几万甚至几十万的资源,如果不能主动释放断开的资源,将造成服务端资源被大量占用。
心跳机制用于避免出现类似的情况,TCP 协议本身具有心跳机制,但需要等待2 小时才会释放资源,这对网络游戏来说,显然是不适用的,因此目前业内主要是自行实现心跳机制,客户端在固定时间间隔给服务端发送PING 协议,服务端在固定时间间隔收到后响应发送PONG 协议;假设服务端在设定时间间隔内因为网络不顺畅或者客户端掉线没有收到PING 协议,则可以判断客户端已经掉线,释放回收该资源用于其他客户端;同样,假设客户端较长时间内没有收到PONG 协议,则认为网络断开或者服务端已经宕机,客户端可以释放自身的资源。
4.数据库存储
网络游戏中的数据量十分庞大,玩家数据有些必须在数据库中进行长期存储,有些只需要临时存储即可,例如用户账号和密码、玩家的金币、等级、装备种类、任务等,这些信息时刻受到玩家关注,需要长期存储,方便玩家上线后进行数据调用;但有些数据,例如玩家的当前位置信息只需临时存储,玩家重新上线后会被重置。在Player对象中设定一个PlayerData 类型的对象,用来保存所有需要存储到数据库的信息,以昵称、金币、等级三个属性为例。代码如下:
游戏开发中使用最多的是MySQL数据库,当服务端与数据库需要进行数据交互时,通过发送SQL语句进行数据的操作,包括新增、修改、读取、删除等操作。配置MySQL数据库分为两个步骤,一是安装MySQL 服务器,开始监听端口;二是使用第三方库来编码和解码MySQL 特定形式的协议。采用Navicat 软件来进行数据库管理,新建数据库名为“game”,新建“account”表和“player”表,如图2所示。
图2 MySQL数据库表
五、服务端运行及测试
服务端框架搭建成功后,如图3 所示,连接成功,服务端启动,开始对服务端进行监听,客户端使用Unity3D游戏引擎进行功能测试,客户端连接、账号注册、登录、心跳机制、客户端断开等功能正常运行。
六、结束语
图3 服务端测试
基于Select多路复用的通用服务端框架是一套功能较为完备的C#通用服务端程序,可用于小规模同时在线,为网络游戏服务端开发商业应用提供了一定的技术参考。