在上一章节里,我们依靠Ace搭建了一个简单的C/S服务器端。现在我们需要设计一个框架用来满足基本的手机五子棋或是纸牌类游戏的需求。通常服务器需要的功能可能需要和数据库相互联系在一起。目前我们先不考虑这个。
既然要处理多个客户端的请求,我们必须设计一个状态客户端和服务器能同时同步的状态。
GameBaseCommand.h
#ifndef_GAMEBASECOMMAND_HEAD
#define_GAMEBASECOMMAND_HEAD
#include"json\json.h"
classGameClient;//游戏客户端
structGameDataStruct{
GameDataStruct(){
value = Json::Value();
}
Json::Value value;
};
//接收命令的类型
enumGameRecvCommandType{
SwitchCommand_Type,//切换类型
ExecuteCommand_Type,//执行命令类型
};
//GameObjecttype
enumGameCommandType{
GeneralCommand_Type,
LoginCommand_Type,
RegisterCommand_Type,
};
//Thebasic command
classGameBaseCommand{
protected:
GameCommandType gameCommandType;//游戏命令
GameRecvCommandType gameRecvCommandType;//游戏接受命令类型
public:
void SetGameCommandType(GameCommandType type){this->gameCommandType = type; }
GameCommandType GetGameCommandType(){ returnthis->gameCommandType; }
void SetGameRecvCommandType(GameRecvCommandTypetype){ this->gameRecvCommandType = type; }
GameRecvCommandType GetGameRecvCommandType(){return this->gameRecvCommandType; }
public:
//服务器处理
virtual void ServerHanding(GameClient*client,GameDataStruct *data) = 0;
//转化自己的命令为数据
virtual GameDataStruct* ConvertSelfToData();
//获取信息
virtual void ReceiveData(GameClient*client,GameDataStruct *data);
//客户端处理
virtual void ClientHanding(GameClient*client,GameDataStruct *data) = 0;
//将数据转化成字符串
inline static std::stringConvertDataToString(GameDataStruct *data){
//处理完成后发送给客户端
Json::FastWriter writer;
std::string str =writer.write(data->value);
return str;
}
//将字符串转化为数据
inline static GameDataStruct*ConvertStringToData(std::string str){
GameDataStruct *r = NULL;
Json::Value value;
Json::Reader reader;
if (reader.parse(str.c_str(),value)){
r = new GameDataStruct();
r->value = value;
}
return r;
}
//发送数据
virtual void SendGameCommand(GameClient*client,GameDataStruct *data);
};
#endif
在以上类定义中我们可以看到,GameBaseCommand定义为抽象类,包含纯虚函数。游戏中所有的状态命令都继承它并实现它。同样也提供了几个函数,主要用于将网络传输得到的字符串转化成命令数据。主要使用了JSON的封装和解析。如果对JSON不太了解的话可以百度到JSONCPP。
我们看具体的实现
GameBaseCommand.cpp
#include"GameBaseCommand.h"
#include"GameClient.h"
#include"ace/SOCK_Stream.h"
GameDataStruct*GameBaseCommand::ConvertSelfToData(){
GameDataStruct *data = new GameDataStruct();
data->value["GameCommandType"] =Json::Value((int)this->gameCommandType);
data->value["GameRecvCommandType"]= Json::Value((int)this->gameRecvCommandType);
return data;
}
voidGameBaseCommand::SendGameCommand(GameClient *client,GameDataStruct *data){
std::string str =this->ConvertDataToString(data);
//进行发送
client->GetSockStream()->send(str.c_str(),strlen(str.c_str())+1,0);
}
//接受信息
voidGameBaseCommand::ReceiveData(GameClient *client,GameDataStruct *data){
//Execute Server Handing
this->ServerHanding(client,data);
//send gameCommand to client.
this->SendGameCommand(client,this->ConvertSelfToData());
}
我们可以看出ReceiveData函数是虚函数,它提供了统一的服务器处理的入口。第一步处理服务器状态命令,第二步将结果返回发送给客户端。当然如果你日后有其他的需求的话,你可以重写它,不用按照它父类所提供的顺序。
以上我们可以看出设计模式在程序开发的重要性,如果我们只是简单的去创建一些类而没有多加思考的话,很容易让代码变得臃肿而且不易扩展。
所以以上就是我设计的初步想法,依靠服务器和客户端之间的状态机进行命令的传输与执行。下一章节会具体讲主要代码编写。