libgsc(Game Server Communication Library)(三)

来源:互联网 发布:centos 安装无线网卡 编辑:程序博客网 时间:2024/05/16 15:09

libgsc的编程方式.


以Db.cpp为例进行说明, 主要是分为三个部分.


1. 业务处理转移表的定义.

转义表中定义了当前actor对自己关注的每个业务的处理函数指针, 为了配置的方便, 命令字被省略, 也就是命令字应该从0x00开始, 可在Db.h

中找到它们的定义.

enum ItcDb{ITC_DB_INIT = 0x00, //ITC_DB_INSERT_SOMETHING,ITC_DB_UPDATE_SOMETHING,ITC_DB_QUERY_SOMETHING,ITC_DB_DELETE_SOMETHING,};
转移表中的CAST_ITC_CB来自于libgsc中的Gsc.h, 以适应不同的pb消息参数, 注ITC(inter-thread communication)

#define CAST_ITC_CB(___X___)      (ushort (*)(Actor* actor, Trans* trans, Msg* msg, Message* oper))(___X___)



2. actor的handle虚函数实现.

handle函数有三个参数, 第一个trans, 当前正在进行的事务, 由发送者开启, 第二个msg, 它携带了发送者/接收者等可能会在业务处理中用

到的信息. 第三个oper, 是msg的消息正文, 这是一个pb消息基类, 是实际的业务内容, 它可以为空, 也就是说, 仅仅使有命令字就可以表达想

要的目的了, handle的实现大同小异, 最终都是根据命令字把worker线程传递的业务消息转移到真正的处理函数中去.

ushort Db::handle(Trans* trans, Msg* msg, Message* oper)


3. 业务代码实现.

参数1, db, 表示谁收到了这个消息, 这里是db对象自己, 参数2,3同上, 参数4, 也是上面的oper. 这个消息是通信双方(发送者和接收者)约定好.

不能出错.

ushort Db::itc_db_init(Db* db, Trans* trans, Msg* msg, ItcComm* itc)

不同的处理结果, 可返回不同的返回值, 在与网络无关的事务中, 返回值暂时没有太多意义, 仅表示处理结果, 如果不调用

trans->forward()函数, 事务总是被结束.

顺便在这里解释一下, actor的事务分为三种, 如下:

enum TransType{TRANS_TYPE_ITC = 0x00, /** ITC事务, 仅限于进程内部消息流转. */TRANS_TYPE_NET_NO_ACTOR, /** 网络上与actor无关的事务. */TRANS_TYPE_NET_ACTOR, /** 网络上与actor有关的事务. */};

上面的Db::itc_db_init是第一种, 事务具体属于哪一种, 是在事务最早被创建时指明, 如itc_db_init消息的在发送时的代码:

Gsc::instance()->sendItc(ITC_DB_INIT, Gas::instance(), Db::instance(), NULL /** 无消息正文. */); /** 尝试数据库初始化. */

另外两种事务, 总是在收到消息时开启, 具体可见GscEvent的实现, 需要说明的是, 与网络有关的事务处理函数返回值有几个约定:

1. 处理函数调用了trans->end(), 这时返回值总是GX_RET_SUCCESS, 但事务会结束, end中的message参数会被发送至客户端.

2. 处理函数调用了trans->forward(), 返回值也总是GX_RET_SUCCESS, 事务被前转.

3. 处理函数没有调用end或forward, 事务总是被结束, 但不同的返回值导致不同的行为:

    a). return GX_RET_SUCCESS, 什么也不做.

    b). return GX_RET_FAILURE, 关闭套接字. 

    c). return 其它返回值, 发送返回值给客户端.


/* * Db.cpp * *  Created on: Aug 6, 2014 5:26:14 PM *      Author: xuzewen */#include "Db.h"#include "Aid.h"#include "NetInit.h"#include "TaskMgr.h"Db* Db::ad = new Db(AID_DB, "Db");/** actor消息处理转移表. */static actor_handle_cb __cb__[] = { ///***/CAST_ITC_CB(Db::itc_db_init),/***/CAST_ITC_CB(Db::itc_db_insert_something),/***/CAST_ITC_CB(Db::itc_db_update_something),/***/CAST_ITC_CB(Db::itc_db_query_something),/***/CAST_ITC_CB(Db::itc_db_delete_something),//};Db::Db(ullong aid, const char* name, int wid) :ActorIdpd(aid, name, wid){this->mysql = NULL;}Db* Db::instance(){return Db::ad;}void Db::reset(){}/** actor消息处理入口. */ushort Db::handle(Trans* trans, Msg* msg, Message* oper){if (msg->cmd >= sizeof(__cb__) / sizeof(actor_handle_cb)){LOG_FAULT("it`s an unexplainable cmd: %04X, from: %s\n", msg->cmd, msg->f->name.c_str())return GX_RET_FAILURE;}if (msg->cmd != ITC_DB_INIT) /** 非初始化消息时, 总是先尝试获得连接. */this->getConn();//return __cb__[msg->cmd].handle(this, trans, msg, oper);}void Db::getConn(){while (this->mysql == NULL){this->mysql = MysqlDb::getConn("host", "usr", "pwd", "db", 3306, "UTF-8");if (this->mysql == NULL){Misc::sleep(1000);continue;}break;}}void Db::close(){MysqlDb::close(this->mysql);this->mysql = NULL;}/*----------------------------------------------------------------*//*                                                                *//*                               消息                              *//*                                                                *//*----------------------------------------------------------------*//** 数据库初始化. */ushort Db::itc_db_init(Db* db, Trans* trans, Msg* msg, ItcComm* itc){Gsc::instance()->regNetInitActor(NetInit::instance()); /** 注册网络初始消息处理器. */ActorMgr::instance()->addActor(Gas::instance()); /** 添加Gas进程. */ActorAuto::instance()->start(TaskMgr::flush); /** 启动actor驱动器. *///if (1 != 1){db->getConn();if (!db->loadGs() || !db->loadGc()) /** 在这里加载数据库到内存. */exit(1);}return trans->forward(ITC_GAS_INIT, db, Gas::instance(), NULL); /** 加载成功后, 前转给Gas. */}/** 插入. */ushort Db::itc_db_insert_something(Db* db, Trans* trans, Msg* msg, ItcComm* itc){return GX_RET_SUCCESS;}/** 更新. */ushort Db::itc_db_update_something(Db* db, Trans* trans, Msg* msg, ItcComm* itc){return GX_RET_SUCCESS;}/** 查询. */ushort Db::itc_db_query_something(Db* db, Trans* trans, Msg* msg, ItcComm* itc){return GX_RET_SUCCESS;}/** 删除. */ushort Db::itc_db_delete_something(Db* db, Trans* trans, Msg* msg, ItcComm* itc){return GX_RET_SUCCESS;}/** 加载所有的GS. */bool Db::loadGs(){static const char* sql = "SELECT UID, USR, PWD, NAME, SRVHOST, SRVPORT, PRVHOST, PRVPORT, UNIX_TIMESTAMP(GTS) FROM TB_GS ORDER BY UID ASC";MYSQL_RES* rst = MysqlDb::getResult(this->mysql, sql);if (rst == NULL)return false;size_t c = 0;MYSQL_ROW row = NULL;while ((row = mysql_fetch_row(rst)) != NULL){//uint uid = 0x00;//MysqlDb::getIntVal(row[0], (int*) &uid);//Gs* gs = new Gs(AID_GS_S + uid, "Gs", Gsc::instance()->randWid(AID_GS_S + uid));/** 构造一个GS-actor对象, 并挂在某个工作线程下. *///gs->uid = uid;//MysqlDb::getStrVal(row[1], &gs->usr);//MysqlDb::getStrVal(row[2], &gs->pwd);//MysqlDb::getStrVal(row[3], &gs->name);//MysqlDb::getStrVal(row[4], &gs->srvhost);//MysqlDb::getIntVal(row[5], &gs->srvport);//MysqlDb::getStrVal(row[6], &gs->prvhost);//MysqlDb::getIntVal(row[7], &gs->prvport);//MysqlDb::getTimeVal(row[8], &gs->gts);//ActorMgr::instance()->addActor(gs);/** 加入到actor管理器. *///GsMgr::instance()->addGs(gs);++c;}MysqlDb::relResult(rst);LOG_INFO("load TB_GS successfully, size: %lu\n", c)return true;}/** 加载所有的GC. */bool Db::loadGc(){static const char* sql = "SELECT UID, USR, PWD, UNIX_TIMESTAMP(GTS) FROM TB_GC ORDER BY UID ASC";MYSQL_RES* rst = MysqlDb::getResult(this->mysql, sql);if (rst == NULL)return false;MYSQL_ROW row = NULL;while ((row = mysql_fetch_row(rst)) != NULL);MysqlDb::relResult(rst);LOG_INFO("load TB_GC successfully, size: %lu\n", 1L)return true;}Db::~Db(){}


其它. 


libgsc的网络报文格式. 

typedef struct{uint len; /** 整个报文长度. */uint tid; /** 事务id. */ushort cmd; /** 命令字. */ushort ret; /** 返回值. */uchar* dat; /** 整个报文. */} gsc_pdu; /** GSC通信报文. */
例: 00 00 00 16 00 00 00 FF 00 00 00 00 0A 03 6B 65 79 12 03 65 78 74

00 00 00 16, 长度, 即整个pdu为22个字节.

00 00 00 FF, 事务ID, 四字节.

00 00, 命令字, 0x00

00 00, 返回值, 

0A 03 6B 65 79 12 03 65 78 74, 消息正文, 序列化后的pb对象.



libgsc中的actor负载均衡,  不同的actor在实际的业务中繁忙程度可能不同, 为避免工作线程有的饥饿, 有的过载, 
可能需在分配aid(actor-id)时详加考虑.







0 0