游戏服务器消息处理机制
一般mmo大型游戏都会有多个服务器进程构成,比如 gate、login、scene、world、db、node(进程节点管理也叫服务器管理服)
只有gate与玩家进行交互,gate接到玩家消息会转发到不同服,不同服进行对消息处理,并返回给gate,gate在将消息发给玩家。
消息通常是使用的都是protobuf。
玩家请求消息,以排行为例:
message rankAsk
{
optional uint64 role_id = 1;
optional int32 rank_type = 2;
}
message rankReply
{
optional int32 rank_sort = 1;
optional int64 rank_score = 2;
}
排行榜的逻辑处理是在world上,gate 获得玩家请求转发给world服,world服需要处理消息并返给gate,在发给玩家
不同进程服通信的消息定义为:
message gate_to_world
{
optional uint64 player_id = 1;
optional uint32 msg_id = 2;
optional bytes msg_body = 3;
}
message world_to_gate
{
optional uint64 player_id = 1;
optional uint32 msg_id = 2;
optional bytes msg_body = 3;
}
world服收到消息后,反序列化得到 gate_to_world 信息,然后在反序列化msg_body得到玩家的请求消息rankAsk。
处理逻辑,在整合成消息rankReply, 填充到world_to_gate 消息 msg_body里,然后发给gate,转发给玩家。这个消息处理的程序逻辑大致如下:
class Packet
{
public:
Packet(){}
Packet(int msgid, ::google::protobuf::Message *msg) : msg_id(msgid), pMsg(msg) {}
~Packet()
{
if(pMsg)
{
delete pMsg;
pMsg = nullptr;
}
}
int msg_id{-1};
::google::protobuf::Message *pMsg{nullptr};
};
class PPacket
{
virtual Packet* CreatePacket(int msg_id, const char* msg, int msglen) = 0;
};
//解析某个消息处理
template <typename T>
class CPacket : public PPacket
{
public:
Packet* CreatePacket(int msg_id, const char* msg, int msglen)
{
T* t = new T;
Packet* packet = new Packet();
t->ParseFromArray(msg, msglen);
packet->msg_id = msg_id;
packet->pMsg = t;
return packet;
}
};
typedef int (*MsgHandle)(Player*, Packet*);
class MessageMgr
{
public:
Packet* CreatePacket(int msg_id, const char* msg, int msglen)
{
auto it = m_mpacket.find(msg_id);
if(it != m_mpacket.end())
{
return it->second->CreatePacket(msg_id, msg, msglen); //进行消息解析
}
}
MsgHandle GetHandle(int msg_id)
{
auto it = m_mhandle->find(msg_id);
if(it != m_mhandle.end())
{
return it->second;
}
}
void registerHandle(int msg_id, MsgHandle handle);
void registerMsg(int msg_id, PPacket* ppacket);
private:
std::map<int, MsgHandle> m_mhandle;
std::map<int, PPacket> m_mpacket;
};
MessageMgr *pMessageMgr;
//每个模块处理每个模块的消息
//这个模块消息可以通过自动生成来完成
class ModuleRank
{
public:
enum MessageID
{
E_RANK_REQ = 1,
};
void ReqRank();
pMessageMgr->registerHandle(E_RANK_REQ, &ModuleRank::ReqRank);
pMessageMgr->registerMsg(E_RANK_REQ, new CPacket<rankAsk>());
}
消息处理逻辑
gate_to_world_message(const char* msg, int len)
{
gate_to_world gate_msg;
gate_msg.ParseFromArray(msg, len);
int nMsgId = gate_msg.msg_id();
//解析出玩家的请求消息,排行榜请求
Packet* packet = pMessageMgr->CreatePacket(nMsgId, gate_msg.msg_body(),gate_msg.msg_body().length());
MsgHandle handle = pMessageMgr->GetHandle(nMsgId);
handle(player, packet); //这里调用ModuleRank::ReqRank 处理消息
}
消息返回则是
world_to_gate_message(int msg_id, const char* msg)
{
world_to_gate world_msg;
world_msg.set_msg_id(msg_id);
world_msg.set_msg_body(msg);
send_gate(E_WORLD_TO_GATE, world_msg);
}
ModuleRank::ReqRank()
{
//处理消息逻辑
//返回消息
world_to_gate_message(int msg_id, const char* msg);
}
参考本人项目实现:
https://github.com/Addision/EventServer/tree/master/Common/packet