1、 前言
struct
connection
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
int use; //该连接是否在使用
int fd; //用于该连接通信的socket
int
最近在看网山下载的石器时代Server的代码,上周看完saac(帐号服务器)后觉得里面有些东西值得借鉴和思考。写本文的目的只是在于抛砖引玉,和各位开发游戏的同志们进行交流。
石器时代是日本人开发的网络游戏,服务器运行在linux下。代码中的注释大部分是日文,所以看的过程中有点痛苦!手上的Server代码全部都是用C写的,整体上分为2部分:gmsv和saac。按照我的理解,gmsv全称应该是game server,是和客户端打交道的游戏服务器;saac全称是stoneage account server,是用于操作后台数据的帐号服务器。目前只看完了saac部分,只能输出这部分的总结,后续看完gmsv后再写对应的心得。
2、saac框架
saac主要包括五部分功能:mail(邮件)、family(家族)、char(角色)、PK、chatroom(聊天室),lock是用于操作帐号相关数据时加锁。可能是当时玩网游的人不是很多,服务器的压力不大,并且当时的机器硬件条件有限,导致saac采用的是单进程实现。这也意味着上面5个功能系统实现时并不是真正设计意义上的子系统划分,采用的是功能函数族,互相之间耦合度较紧。另外,mail、family、char、PK、mission的数据全部都是存储在文件中,所以文件数据读写占了不小的篇幅。
gmsv与saac通信的协议为字符串协议,前2个参数固定为消息id(msgid)、请求消息名称(funcname),后面为该消息的参数,参数个数不定。
3、main详解
saac在main函数中加载完数据和配置文件后,创建了2个监听套结字:mainsockfd和worksockfd。
main主循环流程:
在main函数的while循环中mainsockfd不断接受gmsv发起的连接,接收请求消息内容后调用函数saacproto_ServerDispatchMessage进行分发处理。处理是根据消息中第2个参数funcname调用saacproto_funcname_recv进行请求处理,处理完成后调用saacproto_funcname_send发送响应结果。实际上saacproto_funcname_recv会调用funcnam对应功能子系统的簇函数进行数据操作,如果数据涉及到用户帐号,如char、family等操作前需要向lock部分请求加锁,只有加锁成功后才能对数据进行操作。
worksockfd用于接收saac内部的请求消息,调用该请求对应的回调函数,如charLoadCallback(角色数据加载)、charListCallback(列举用户帐号所有角色)、charDeleteCallback(删除角色)等。当初看到这个worksockfd时,以为会启动一个单独的进程进行这些操作,结果没想到还是在一个进程里做。
4、 套接字缓冲区
saac管理连接使用的数据结构是connection,定义如下:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/1327ab569c1ae82736693a50b8e33378.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)