转行做游戏(2) Kbengine serverapp结构初步解析
来源:互联网 发布:java 预测算法 编辑:程序博客网 时间:2024/06/05 02:35
前言
本文使用machine为例进行说明。为什么是的是Machine呢?这个还得从keb启动脚本说起。以start_server.bat为例start_server.bat一开始巴拉巴拉一大堆。然后启动的第一个appstart %KBE_BIN_PATH%/machine.exe --cid=1000 --gus=1启动了machine。So..
正文
当然了我们也是从main函数开始
main 函数
...int KBENGINE_MAIN(int argc, char* argv[]){#if KBE_PLATFORM != PLATFORM_WIN32 rlimit rlimitData = { RLIM_INFINITY, RLIM_INFINITY }; setrlimit(RLIMIT_CORE, &rlimitData);#endif ENGINE_COMPONENT_INFO& info = g_kbeSrvConfig.getKBMachine(); int ret = kbeMainT<Machine>(argc, argv, MACHINE_TYPE, info.externalPorts_min, info.externalPorts_max, "", 0, info.internalInterface); return ret; }...
KBENGINE_MAIN的定义
#if KBE_PLATFORM == PLATFORM_WIN32#define KBENGINE_MAIN \kbeMain(int argc, char* argv[]); \int main(int argc, char* argv[]) \{ \ loadConfig(); \ g_componentID = genUUID64(); \ parseMainCommandArgs(argc, argv); \ char dumpname[MAX_BUF] = {0}; \ kbe_snprintf(dumpname, MAX_BUF, "%"PRAppID, g_componentID);\ KBEngine::exception::installCrashHandler(1, dumpname); \ int retcode = -1; \ THREAD_TRY_EXECUTION; \ retcode = kbeMain(argc, argv); \ THREAD_HANDLE_CRASH; \ return retcode; \} \int kbeMain#else#define KBENGINE_MAIN \kbeMain(int argc, char* argv[]); \int main(int argc, char* argv[]) \{ \ loadConfig(); \ g_componentID = genUUID64(); \ parseMainCommandArgs(argc, argv); \ return kbeMain(argc, argv); \} \int kbeMain#endif
KBENGINE_MAIN干了些啥
KBENGINE_MAIN让所有的app都做了3件事,loadConfig();//载入配置信息,必须要说的事,这只是载入基本配置,如果是app特有的配置后续还会有g_componentID = genUUID64();//生成app进程的唯一标示parseMainCommandArgs(argc, argv);//解析Command参数,其实只有3种。 --cid=,--gus=还有--hide=
KBENGINE_MAIN定义的疑惑
在这里应该有两个疑惑:
Resmgr 重复初始化
在Machine中就存在某个全局变量导致Resmgr::getSingleton().initialize();在main之前就执行过一次。奇怪的是initialize()原本是 有判断是否有过初始化的,但是被注释掉了。
Command --gus= 参数无意义
在genUUID64()中会根据g_genuuid_sections是否为有效值而使用两种不同的方式生成uuid。but,令人惊讶是的g_genuuid_sections是Command中的--gus=。而Command的解析居然在genUUID64()之后。
QTMD,不管了,我们接着说表面的Main函数。
kbemain
这里使用了模板kbeMainTkbeMainT 的构造函数
我已经把打印日志的代码去掉了,这样看上去会简洁那么一丢丢。。
template <class SERVER_APP>int kbeMainT(int argc, char * argv[], COMPONENT_TYPE componentType, int32 extlisteningPort_min = -1, int32 extlisteningPort_max = -1, const char * extlisteningInterface = "", int32 intlisteningPort = 0, const char * intlisteningInterface = ""){ setEvns(); startLeakDetection(componentType, g_componentID); g_componentType = componentType; DebugHelper::initialize(componentType); KBEKey kbekey(Resmgr::getSingleton().matchPath("key/") + "kbengine_public.key", Resmgr::getSingleton().matchPath("key/") + "kbengine_private.key"); Network::EventDispatcher dispatcher; DebugHelper::getSingleton().pDispatcher(&dispatcher); const ChannelCommon& channelCommon = g_kbeSrvConfig.channelCommon(); Network::g_SOMAXCONN = g_kbeSrvConfig.tcp_SOMAXCONN(g_componentType); Network::NetworkInterface networkInterface(&dispatcher, extlisteningPort_min, extlisteningPort_max, extlisteningInterface, channelCommon.extReadBufferSize, channelCommon.extWriteBufferSize, (intlisteningPort != -1) ? htons(intlisteningPort) : -1, intlisteningInterface, channelCommon.intReadBufferSize, channelCommon.intWriteBufferSize); DebugHelper::getSingleton().pNetworkInterface(&networkInterface); g_kbeSrvConfig.updateInfos(true, componentType, g_componentID, networkInterface.intaddr(), networkInterface.extaddr()); Components::getSingleton().initialize(&networkInterface, componentType, g_componentID); SERVER_APP app(dispatcher, networkInterface, componentType, g_componentID); Components::getSingleton().findLogger(); START_MSG(COMPONENT_NAME_EX(componentType), g_componentID); if(!app.initialize()) { Components::getSingleton().finalise(); app.finalise(); // 如果还有日志未同步完成, 这里会继续同步完成才结束 DebugHelper::getSingleton().finalise();#if KBE_PLATFORM == PLATFORM_WIN32 // 等待几秒,让用户能够在窗口上看到信息 Beep(587, 500); KBEngine::sleep(5000);#endif return -1; } int ret = app.run(); Components::getSingleton().finalise(); app.finalise(); // 如果还有日志未同步完成, 这里会继续同步完成才结束 DebugHelper::getSingleton().finalise(); return ret;}
我们用广度优先的方式解读代码。
setEvns();//设置了一些环境变量startLeakDetection(componentType, g_componentID);//在machine中啥也没干。其他app中还不知道,这个暂不细究。DebugHelper::initialize(componentType);//跟了一下,好深~~不过,就是初始化一下日志什么的,先不深究,啦啦啦啦~~好多不深究。恩,我们是为了把精力放到更重要的地方,毕竟学海无涯而吾生有涯~~~KBEKey kbekey(Resmgr::getSingleton().matchPath("key/") + "kbengine_public.key", Resmgr::getSingleton().matchPath("key/") + "kbengine_private.key");//载入了一下公私key,还做了下对比,标示了下kbekey'是否有效Network::EventDispatcher dispatcher;//一个事件处理器,这个玩意会对event的增加,减少,执行进行处理,当然,它本身没有实现执行,只是调用DebugHelper::getSingleton().pDispatcher(&dispatcher);//设置了下处理器,并且启动的DebugHelper的timer//巴拉巴拉 各种初始化,包裹network的参数,srcConfig的各种参数const ChannelCommon& channelCommon = g_kbeSrvConfig.channelCommon();Network::g_SOMAXCONN = g_kbeSrvConfig.tcp_SOMAXCONN(g_componentType);Network::NetworkInterface networkInterface(&dispatcher, extlisteningPort_min, extlisteningPort_max, extlisteningInterface, channelCommon.extReadBufferSize, channelCommon.extWriteBufferSize,(intlisteningPort != -1) ? htons(intlisteningPort) : -1, intlisteningInterface,channelCommon.intReadBufferSize, channelCommon.intWriteBufferSize);DebugHelper::getSingleton().pNetworkInterface(&networkInterface);g_kbeSrvConfig.updateInfos(true, componentType, g_componentID, networkInterface.intaddr(), networkInterface.extaddr());Components::getSingleton().initialize(&networkInterface, componentType, g_componentID);//初始化了一下app需要查找的app。当然了,Machine不需要任何app
下面就是重点了
SERVER_APP app(dispatcher, networkInterface, componentType, g_componentID);Components::getSingleton().findLogger();//查找logger,当然了 Machine 又不需要if(!app.initialize())//初始化app各种东西,绝对的重要。。欲知详情,请听下回分解,还在本章哦~~~~{...//初始化失败了当然就是滚蛋了,有什么好说的}int ret = app.run();// app的主循环了,出来就已经gg了,//后面的暂时不管了,反正已经gg了,不重要了哈哈哈
ServerApp::initialize()
bool ServerApp::initialize(){ if(!initThreadPool())return false;//初始化线程池 if(!installSignals())return false;//注册信号 if(!loadConfig())return false;//载入特有的配置,通用配置已经在开始前就载入了 if(!initializeBegin())return false;//初始化前的准备 if(!inInitialize())return false;//初始化 bool ret = initializeEnd();//初始化后续处理#ifdef ENABLE_WATCHERS return ret && initializeWatcher();#else return ret;#endif}在Machine中并没有其他的配置需要载入。
1.initializeBegin()
Machine初始化了NetWork,分别对epBroadcast_,ep_,epLocal_三个监听做了初始化。监听的端口分别是20086,20087,20088端口,实际使用还未可知。后续再看。
epBroadcast_.socket(SOCK_DGRAM);
ep_.socket(SOCK_DGRAM);
epLocal_.socket(SOCK_DGRAM);
2.inInitialize()
在Machine中并没有做什么特有的初始化动作3.initializeEnd()
在Machine中因为并不需要依赖其他app所以也没做什么bool Machine::run()
接下来就是run()了bool Machine::run(){ bool ret = true; while(!this->dispatcher().hasBreakProcessing())//这句话比较简单,就是检测下app是否该结束了 { threadPool_.onMainThreadTick();//这个对finiTaskList_列表做了处理,把准备好,可以开始处理的放到worker中,处理玩的删除,还未准备好的放回原队 this->dispatcher().processOnce(false);//处理了一下主线程中的事务 networkInterface().processChannels(&MachineInterface::messageHandlers);//获取Network中的任务 KBEngine::sleep(100); }; return ret;}
到现在,Machine中的逻辑基本清楚了。
各种初始化之后,分为主线程和worker线程两个部分处理事务。
主线程是处理network的事务,显然是不可以被阻塞的,那么有一些可能会阻塞的任务就会交给worker线程。
处理完之后还是回发给network。
ServerApp的Message定义方式
Machine会处理的Message
这个可以在machine_interface.h 中可以查看到// 其他组件向app广播自己的接口地址MACHINE_MESSAGE_DECLARE_ARGS25(onBroadcastInterface, NETWORK_VARIABLE_MESSAGE, int32, uid, std::string, username, COMPONENT_TYPE, componentType, COMPONENT_ID, componentID, COMPONENT_ID, componentIDEx, COMPONENT_ORDER, globalorderid, COMPONENT_ORDER, grouporderid, COMPONENT_GUS, gus, uint32, intaddr, uint16, intport, uint32, extaddr, uint16, extport, std::string, extaddrEx, uint32, pid, float, cpu, float, mem, uint32, usedmem, int8, state, uint32, machineID, uint64, extradata, uint64, extradata1, uint64, extradata2, uint64, extradata3, uint32, backRecvAddr, uint16, backRecvPort)// 其他组件向app请求获取某个组件类别的地址 MACHINE_MESSAGE_DECLARE_ARGS7(onFindInterfaceAddr, NETWORK_VARIABLE_MESSAGE, int32, uid, std::string, username, COMPONENT_TYPE, componentType, COMPONENT_ID, componentID, COMPONENT_TYPE, findComponentType, uint32, addr, uint16, finderRecvPort)// 查询所有接口信息MACHINE_MESSAGE_DECLARE_ARGS3(onQueryAllInterfaceInfos, NETWORK_VARIABLE_MESSAGE, int32, uid, std::string, username, uint16, finderRecvPort)// 查询所有machine进程MACHINE_MESSAGE_DECLARE_ARGS3(onQueryMachines, NETWORK_VARIABLE_MESSAGE, int32, uid, std::string, username, uint16, finderRecvPort)// 某app主动请求look。MACHINE_MESSAGE_DECLARE_ARGS0(lookApp, NETWORK_FIXED_MESSAGE)// 某个app请求查看该app负载状态。MACHINE_MESSAGE_DECLARE_ARGS0(queryLoad, NETWORK_FIXED_MESSAGE)// 启动服务器MACHINE_MESSAGE_DECLARE_STREAM(startserver, NETWORK_VARIABLE_MESSAGE)// 关闭服务器MACHINE_MESSAGE_DECLARE_STREAM(stopserver, NETWORK_VARIABLE_MESSAGE)// 关闭服务器MACHINE_MESSAGE_DECLARE_STREAM(killserver, NETWORK_VARIABLE_MESSAGE)// 请求强制杀死当前appMACHINE_MESSAGE_DECLARE_STREAM(reqKillServer, NETWORK_VARIABLE_MESSAGE)
Message定义展开
我们以MACHINE_MESSAGE_DECLARE_ARGS7(onFindInterfaceAddr, NETWORK_VARIABLE_MESSAGE, int32, uid, std::string, username, COMPONENT_TYPE, componentType, COMPONENT_ID, componentID, COMPONENT_TYPE, findComponentType, uint32, addr, uint16, finderRecvPort)
为例进行扩展,打开之后的代码为
class onFindInterfaceAddrMachineMessagehandler7 : public Network::MessageHandler{public: void handle(Network::Channel* pChannel, KBEngine::MemoryStream& s) { int32 uid; s >> uid; std::string username; s >> username; COMPONENT_TYPE componentType; s >> componentType; COMPONENT_ID componentID; s >> componentID; COMPONENT_TYPE findComponentType; s >> findComponentType; uint32 addr; s >> addr; uint16 finderRecvPort; s >> finderRecvPort; KBEngine::Machine::getSingleton().NAME(pChannel, uid, username, componentType, componentID, findComponentType, addr, finderRecvPort); }};extern const onFindInterfaceAddrMachineMessagehandler7& onFindInterfaceAddr;class onFindInterfaceAddrArgs7 : public Network::MessageArgs { public: int32 uid; std::string username; COMPONENT_TYPE componentType; COMPONENT_ID componentID; COMPONENT_TYPE findComponentType; uint32 addr; uint16 finderRecvPort;public: onFindInterfaceAddrArgs7():Network::MessageArgs() { strArgsTypes.push_back("int32"); strArgsTypes.push_back("std::string"); strArgsTypes.push_back("COMPONENT_TYPE"); strArgsTypes.push_back("COMPONENT_ID"); strArgsTypes.push_back("COMPONENT_TYPE"); strArgsTypes.push_back("uint32"); strArgsTypes.push_back("uint16"); } onFindInterfaceAddrArgs7( int32 init_uid, std::string init_username, COMPONENT_TYPE init_componentType, COMPONENT_ID init_componentID, COMPONENT_TYPE init_findComponentType, uint32 init_addr, uint16 init_finderRecvPort): Network::MessageArgs(), uid(init_uid), username(init_username), componentType(init_componentType), componentID(init_componentID), findComponentType(init_findComponentType), addr(init_addr), finderRecvPort(init_finderRecvPort) { strArgsTypes.push_back("int32"); strArgsTypes.push_back("std::string"); strArgsTypes.push_back("COMPONENT_TYPE"); strArgsTypes.push_back("COMPONENT_ID"); strArgsTypes.push_back("COMPONENT_TYPE"); strArgsTypes.push_back("uint32"); strArgsTypes.push_back("uint16"); } ~onFindInterfaceAddrArgs7(){} static void staticAddToBundle(Network::Bundle& s, int32 init_uid, std::string init_username, COMPONENT_TYPE init_componentType, COMPONENT_ID init_componentID, COMPONENT_TYPE init_findComponentType, uint32 init_addr, uint16 init_finderRecvPort) { s << init_uid; s << init_username; s << init_componentType; s << init_componentID; s << init_findComponentType; s << init_addr; s << init_finderRecvPort; } static void staticAddToStream(MemoryStream& s, int32 init_uid, std::string init_username, COMPONENT_TYPE init_componentType, COMPONENT_ID init_componentID, COMPONENT_TYPE init_findComponentType, uint32 init_addr, uint16 init_finderRecvPort) { s << init_uid; s << init_username; s << init_componentType; s << init_componentID; s << init_findComponentType; s << init_addr; s << init_finderRecvPort; } virtual int32 dataSize(void) { return sizeof(int32) + sizeof(std::string) + sizeof(COMPONENT_TYPE) + sizeof(COMPONENT_ID) + sizeof(COMPONENT_TYPE) + sizeof(uint32) + sizeof(uint16); } virtual void addToStream(MemoryStream& s) { s << uid; s << username; s << componentType; s << componentID; s << findComponentType; s << addr; s << finderRecvPort; } virtual void createFromStream(MemoryStream& s) { s >> uid; s >> username; s >> componentType; s >> componentID; s >> findComponentType; s >> addr; s >> finderRecvPort; } };
这个是我手工展开的,所以很能有cp错误什么的。。看下就好了。不知道有什么工具能把宏展开~~~~(说不得哪天闲的蛋疼,我就自己写一个小工具,报着亿万分之一的可能性来期待吧,哈哈哈)
看上去还是很规则的。基本就是定义了下Machine的Message的生成什么的。然后在handle方法中调用了Machine的对应接口。
值得一提的是我在使用vs2015进行跟进的时候。得到进入的到handle是一个没有实现的虚函数。。。折腾了好久,最后查询了下
MACHINE_MESSAGE_HANDLER_STREAM
的所有定义,然后发现了我想要的结果,接着做了下小小的测试。
MACHINE_MESSAGE_HANDLER_STREAM确实是使用的这个展开的定义。
看了下整体结构,应该是只有app自身在定义属于自身的Message的时候才会产生回调。其他时候则只是普通的消息。
/*这里搞错了,这个宏是会被展开两次的,第一次定义了class的虚函数,第二次定义了实现,如果是属于自身的就会回调,反之则不做处理*/
0 0
- 转行做游戏(2) Kbengine serverapp结构初步解析
- 转行做游戏(1) 编译kbengine
- Kbengine游戏服务器搭建
- 准备使用kbengine做项目
- Android Databinding 从入门到转行(一)初步介绍
- KBEngine
- KBEngine
- Java游戏编程初步(2)
- 2D游戏初步
- kbengine做无限大世界之架构分析
- 非常强的一款开源的分布式游戏服务端引擎(kbengine)
- 程序员转行做什么?
- 转行做手机驱动
- 转行做程序员
- 如何转行做程序员
- kbengine引擎服务端目录结构分析
- kbengine引擎服务端目录结构分析
- kbengine引擎服务端目录结构分析
- 听指挥的小孩——项目拾金(一)
- LintCode : 链表排序
- JAVA 线程池
- 如何利用session在页面中调用
- 图像处理与计算机视觉基础相关领域的经典书籍以及论文
- 转行做游戏(2) Kbengine serverapp结构初步解析
- FindBug异常总结
- c#递归方法调用
- 新手常见问题解答
- 无题
- 云盘系统批量删除文件目录方法(亲测)
- linux shell 学习(九)——函数基本使用
- Android动画之萌萌哒蜡烛吹蜡烛动画
- LPC17XX 学习之 uCOS-II 移植实例