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.