这个版本基本上达到了我最早想要的效果: 简洁, 直观, 无锁, 并行, 高效. 高效不一定是运行时的效率, 更多的是开发效率. 也就是最少的bug
产生可能性, 最快的代码实现.
代码实际上在2月份就基本完工了, 等到经历了一个html5的游戏后, 感觉应该差不多了. 不太可能再有大的改动. 另外, 也添加了一些功能.
这些功能也导致我重新修改了通信协议. 一起汇总如下:
1. Actor的调度/通信的基本原理未变, 依然是基于epoll, pipe. 只是管道上的通信仅仅作为唤醒目标工作线程的目的, 不承载业务属性. 相信要
高效得多. 还是不支持windows平台.
2. 应用层的协议使用了此博客中提到的stmp协议. 主要是考虑到编解码的自动化和可扩展性. 业务消息依然使用protobuf(2.6.1).
3. 提供了websocket的实现, 且支持在同一端口上同时使用stmp和websocket作为承载, 但websocket的上层还是必需使用stmp协议.
4. 提供了tcp短连接支持.
5. 网络消息依然采用注册加回调的形式, libgsc提供了几个宏, 用于支持不同的业务消息注册. 如:
REG_N2H_NOGUSR(GAS_REQ_GC_AUTH, GcAuthWithGasReq, GcAuthWithGasRsp, GcMsgAuth::gas_req_gc_auth)表示:
a). 注册一个GAS_REG_GC_AUTH的命令字(short),
b). 请求消息是GcAuthWithGasReq(pb生成的c++类)
c). 响应消息是GcAuthWithGasRsp.
d). 消息到来时的处理函数是: GcMsgAuth::gas_req_gc_auth
6. 网络事务处理透明化, 假想一个玩家(Game Client)登录的请求处理如下:
void GcMsgAuth::gas_req_gc_auth(N2H* n2h, Gn2htrans* gt, GcAuthWithGasReq* req)
{
GcAuthWithGasRsp* rsp = new GcAuthWithGasRsp();
if(req->usr() == "usr" && req->pwd() == "pwd")
rsp->set_rsp("login ok");
else
rsp->set_rsp("login fail");
gt->end(rsp);
}
Gn2htrans表示了一个由TCP客户端发起的消息事务. 在填充好rsp后, 通过调用gt->end(rsp); 响应结果就会被发送到客户端. 有点类似
在java-sevlet中加入了一个事务的概念. 区别在于, 这个事务不一定要立即结束. 下面第8点详述.
7. Actor的所有通信都基于lambda, 面向future(调用Actor的future函数)的编程模式. 例如:
Db* db = this->getDb();
db->future([db]
{
db.load();
});调用db->future的线程可能早就返回了. 这在有网络请求需要访问数据库后才返回的场景下会使代码量变得非常小, 且十分直观. 貌似libcaf和akka
都没有提供类似的功能. 如下面的代码:
void GcMsgAuth::gas_req_gc_auth(N2H* n2h, Gn2htrans* gt, GcAuthWithGasReq* req)
{
Db* db = this->getDb(); //thread-0
db->future([db, gt, req]
{
GcAuthWithGasRsp* rsp = new GcAuthWithGasRsp(); //thread-1
if(db.auth(req->usr(), req->pwd()))
rsp->set_rsp("login ok");
else
rsp->set_rsp("login fail");
gt->end(rsp); //事务结束.
});
}
在收到客户端的登录请求后, 取出一个db-actor, 并通过同步调用db.auth前往数据库验证用户名/密码的正确性后, 再将事务响应.
业务消息的开发人员不需要关心请求/响应与事务的内存释放. 减少bug的发生机率.另外, 事务在结束时, 可以将req和rsp吐出到日志输出功能, 这在调试
和运营日志输出时非常有用.
GsAuthWithGasReq* req = new GsAuthWithGasReq();
h2nActor->future(0x0001, req, [this](ushort ret, Message* r)
{
if(ret != RET_SUCCESS) /** 失败. */
return;
GsAuthWithGasRsp* rsp = (GsAuthWithGasRsp*)r;
LOG_INFO("auth with GAS successfully: %s\n", rsp->ShortDebugString().c_str())
},
/** timeout 回调. */
[this, req]
{
LOG_WARN("timeout, req: %s\n", req->ShortDebugString().c_str())
this->close();
});
h2nActor应该继承自H2N基类. h2n的future函数提供了两个lambda表达式, 一个是响应到来时回调, 另一个是超时到来时回调.
这两个lambda都在h2nActor所处的线程中被调用. 非常安全.
10. 提供了消息加/解密接口.
11. 零配置或零配置文件.
12. 代码已上传至github, 一并提供了java版本的实现. 由于libgsc是使用的c++验证想法, 且经历了一个实际的项目, 因此暂时以c++的版本为主, java版暂
作为功能移植版本, 但基本上保持一致. 让时间来完善它们: https://github.com/xzwdev/libgsc
libgsc(Game Server Communication Library)(五)
原文地址:http://blog.csdn.net/xzwdev/article/details/46312831