Client->request Server->response模式的网络服务器中,对应答的处理一般是采用switch模式。
此方法比较难于维护,且缺少错误检测。
本文采用C++模板实现一套较为通用的服务器命令处理模型。
阅读本文你应该对C++模板较为熟悉。
ok,进入正题。
假定客户命令包头为。
struct MsgHead{
DWORD type;
};
定义客户端命令模板类。
template<DWORD reqCode>
class RequestT:protected MsgHead{
STATIC_CHECK(0,REQUEST_NOT_DEFINED);
};
定义宏对具体命令做偏特化。
#define DECL_REQUEST(reqCode)/
template<>/
class RequestT<reqCode>:public MsgHead{/
friend class RequestHandlerT<reqCode>;/ //处理函数
RequestT<reqCode>(){}
#define END_DECL(code)/
};
定义回应类
template<DWORD resCode,DWORD reqCode>
class ResponseT:protected MsgHead{
STATIC_CHECK(0,REQUEST_NOT_DEFINED);
};
偏特化
#define DECL_RESPONSE(reqCode,resCode)/
template<>/
class ResponseT<resCode>:public MsgHead{/
friend class RequestHandlerT<reqCode>;/ //处理函数
ResponseT<resCode>(){type=resCode;}
定义处理函数.
typedef int CommandHandler(MsgHead* in,MsgHead* out);
处理函数模板
template <DWORD code>
class HandlerT{
static int Handle(MsgHead*in,MsgHead* out);
};
定义命令映射表格
struct cmd_set{
DWORD dwRequest;
CommandHandler* pHandler;
};
定义命令映射宏
#define MAP_CMD(code)/
{code, HandlerT<code>::Handle},
ok,整个架构以基本搭建好了。
现在来写一个简单的命令处理试试。
//客户端请求
enum{
CR_CONNECT,
};
//服务器回应
enum{
SR_OK,
SR_DENY
};
//请求包格式
DECL_REQUEST(CR_CONNECT)
WORD wReason;
DWORD dwVerify;
END_DECL(CR_CONNECT)
//成功回应格式
DECL_RESPONSE(CR_CONNECT,SR_OK)
DWORD dwConnectionID
END_DECL(CR_CONNECT)
//拒绝包回应格式
DECL_RESPONSE(CR_CONNECT,SR_DENY)
DWORD dwError;
END_DECL(CR_CONNECT)
//处理函数
template<>
class HandlerT<CR_CONNECT>{
static int Handle(MsgHead*in,MsgHead*out){
MsgRequestT<CR_CONNECT>* pIn=static_cast<MsgRequest<CR_CONNECT>*>(in);
switch(pIn.wReason){
......
}
.....
return out包长度
}
}
建立映射表
cmd_set Cmd_MAP[]={
MAP_CMD(CR_CONNECT)
..................
};
主函数中通过wType查找Cmd_MAP找到处理函数后调用函数处理包。
//==============================================================================
上面的模型可以用宏进一步减少工作量。(如HandlerT<>等)
另外MsgHead及其派生类(各种request/response)都不应该允许被实例化,否则处理函数可能出错(处理函数并不知道实际可写包长)。
可以将MsgHead构造函数声明为protected的。只将可以被实例化的实际子类声明为public.