In a network server in client-> request server-> response mode, the switch mode is generally used for response processing.
This method is difficult to maintain and lacks error detection.
This document uses the C ++ template to implement a common server command processing model.
Read this article and you should be familiar with the c ++ template.
OK.
Assume that the customer command header is.
Struct msghead {
DWORD type;
};
Define the Client Command template class.
Template <DWORD reqcode>
Class requestt: protected msghead {
Static_check (0, request_not_defined );
};
The definition macro is biased towards specific commands.
# Define decl_request (reqcode )/
Template <>/
Class requestt <reqcode>: Public msghead {/
Friend class requesthandlert <reqcode>; // processing function
Requestt <reqcode> (){}
# Define end_decl (CODE )/
};
Define response class
Template <DWORD rescode, DWORD reqcode>
Class responset: protected msghead {
Static_check (0, request_not_defined );
};
Bitrate
# Define decl_response (reqcode, rescode )/
Template <>/
Class responset <rescode>: Public msghead {/
Friend class requesthandlert <reqcode>; // processing function
Responset <rescode> () {type = rescode ;}
Define the processing function.
Typedef int commandhandler (msghead * In, msghead * out );
Processing Function Template
Template <DWORD code>
Class handlert {
Static int handle (msghead * In, msghead * out );
};
Define command ing table
Struct cmd_set {
DWORD dwrequest;
Commandhandler * phandler;
};
Define command ing macro
# Define map_cmd (CODE )/
{Code, handlert <code >:: handle },
OK. The entire architecture is basically set up.
Now let's try to write a simple command.
// Client request
Enum {
Cr_connect,
};
// Server response
Enum {
Sr_ OK,
Sr_deny
};
// Request package format
Decl_request (cr_connect)
Word wreason;
DWORD dwverify;
End_decl (cr_connect)
// Response format
Decl_response (cr_connect, sr_ OK)
DWORD dwconnectionid
End_decl (cr_connect)
// Response format
Decl_response (cr_connect, sr_deny)
DWORD dwerror;
End_decl (cr_connect)
// Processing functions
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 package Length
}
}
Create a ing table
Pai_set pai_map [] = {
Map_cmd (cr_connect)
..................
};
In the main function, find the handler _map through wtype and call the function Processing Package.
// ================================================ ==========================================================
The above model can be further used to reduce the workload. (Such as handlert <>)
In addition, msghead and Its Derived classes (various request/Response) should not be allowed to be instantiated. Otherwise, the processing function may fail (the processing function does not know the actual writable package length ).
You can declare the msghead constructor as protected. Declare only the actual subclass that can be instantiated as public.