前言
本文使用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)
// 请求强制杀死当前app
MACHINE_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的虚函数,第二次定义了实现,如果是属于自身的就会回调,反之则不做处理*/