框架浅记二

2.消息包的处理(protobuffer)

二、

1.先看看框架代码目录结构:

2.以下以loginGroup登录组业务模块为例,其他业务模块结构都基本相同。

3.首先从network网路模块核心说起。

核心类类图如下:

4.stFrontServer初始化调用listenAt,参数IOhandle最终传到tcpSocket类中,在监听doRead()收到客户端消息解包时,通过调用IOhandle的postNewMsg(constnetLinkPtrpNetLink,uint64uid,uint32cmd,constmsgBufPtrpBuff),从而达到执行业务逻辑的消息包的回调。

boolstNetWork::listenAt(uint16port,stIOHandler*pHandler,boolopenPing,conststd::stringlinkType){

autoiterF=mAccepterMap.find(port);

if(iterF!=mAccepterMap.end()){

log_error("listenport[%u]faild,porthaslistend",port);

returnfalse;

}

if(NULL==pHandler){

log_error("listenport[%u]msgHandlerisNULL",port);

returnfalse;

}

acceptPtrpAccept(newstAccepter(mIos,pHandler,linkType,openPing));

if(!pAccept-listen(port)){

log_error("listenport[%u]faild!",port);

returnfalse;

}

mAccepterMap[port]=pAccept;

returntrue;

}

5.再具体看看stAccpter具体做了啥,socket实例化和bind,connect,循环监听等

boolstAccepter::listen(uint16listenPort){

try{

boost::asio::ip::tcp::resolverres(mIos);

boost::asio::ip::tcp::endpointep(boost::asio::ip::address::from_string("0.0.0.0"),listenPort);

mAcceptor.open(ep.protocol());

mAcceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));

mAcceptor.bind(ep);

mAcceptor.listen();

doAccept();

log_debug("[%s]listenat:%usuccess",mIOHandler-getName().c_str(),listenPort);

}catch(boost::system::system_errorec){

log_error("[%s]listenat:%ufaild,error:[%s]",mIOHandler-getName().c_str(),listenPort,ec.what());

returnfalse;

}

returntrue;

}

voidstAccepter::doAccept(){

mAcceptor.async_accept(mNewSocket,mNewEndPoint,mStrand.wrap([this](boost::system::error_codeec)

{

if(ec==boost::asio::error::operation_aborted){

return;

}

if(!mAcceptor.is_open()){

log_error("acceptisnotopen");

return;

}

do{

if(ec){

log_error("accepterror");

break;

}

netLinkPtrpNetLink=newNetLink(mLinkType,mIos,mNewSocket,mNewEndPoint,mIOHandler,this);

if(NULL!=pNetLink){

onConnect(pNetLink);

pNetLink-onConnect(true);

}

}while(0);

doAccept();

})

);

}

6,在4中,要做消息的回调,使用的是函数指针的方式。在每一个业务模块(继续IOhandle)里肯定会有多个消息号要处理。这时就stMessageHandler上场了,每一个业务模块里会申明一个。stMessageHandler它里面有个mapuint16,msgHandlerFuncmFuncMap,key为消息号id,value为函数指针。在业务类stClientMsgHandler中实现父类的onNewMsg接口里则调用这个函数指针,从而执行完毕,完成一个从收包到处理消息逻辑的完整流程。

7.这里以客户端发送连接消息为例,并体会下宏的使用.在类stClientMsgHandler中:

virtualvoidonNewMsg(constnetLinkPtrpSocket,uint64uid,uint32cmd,constmsgBufPtrbuff){

//...

mMsgHandle.handleMsg(pSocket,uid,cmd,buff)

}

virtualboolinitMsgHandle(){

REGISTER_CMD(cl2fr_connect_request)//注册,展开如下//mMsgHandle.regFunc(op_cmd::cl2fr_connect_request,handle_cl2fr_connect_request);

}

stMessageHandlermMsgHandle;

DEC_HANDLE_MSG(cl2fr_connect_request);//.h申明,展开如下

//staticboolhandle_cl2fr_connect_request(constnetwork::netLinkPtrs,uint64uid,constnetwork::msgBufPtrmsgBuf);

DEF_HANDLE_BEGIN(stClientMsgHandler,server,cl2fr_connect_request){//.cpp定义

stClientManager::onSDKLogin(s,msg.account_no(),msg.platform(),msg.opid());

}

//展开如下

boolstClientMsgHandler::handle_cl2fr_connect_request(constnetLinkPtrs,uint64uid,constmsgBufPtrmsgBuf){

UNWRAP_MSG(proto::client::cl2fr_connect_request);

stClientManager::onSDKLogin(s,msg.account_no(),msg.platform(),msg.opid());

}

8.下面看看宏的定义:

#defineREGISTER_CMD_LINK(handleName,name)\

handleName::regHandleFunc(op_cmd::name,handle_##name);

#defineREGISTER_CMD(name)\

mMsgHandle.regFunc(op_cmd::name,handle_##name);

#defineDEC_HANDLE_MSG(name)\

staticboolhandle_##name(constnetwork::netLinkPtrs,uint64uid,constnetwork::msgBufPtrmsgBuf);

#defineDEF_HANDLE_BEGIN(type,side,name)\

booltype::handle_##name(constnetwork::netLinkPtrs,uint64uid,constnetwork::msgBufPtrmsgBuf){\

UNWRAP_MSG(proto::side::name);\

if(true==gLogger.mLogContral.decodeMsg){\

log_msg("msgdecode[%s]",msg.Utf8DebugString().c_str());\

}

9.注意解包的宏:UNWRAP_MSG

//解包

templatetypenameT_MSG

staticboolunWrapMsg(T_MSGmsg,constmsgBufPtrbuf){

if(buf-isCompress()){

charuzBuf[PACKET_MAX_SIZE]={0};

bzero(uzBuf,sizeof(uzBuf));

uLongfbufSize=PACKET_MAX_SIZE;

int32retcode=un



转载请注明地址:http://www.xqopn.com//zcmbwh/92982.html
  • 上一篇文章:
  • 下一篇文章: