游戏服务器之逻辑服务器和数据服务器的异步通信

本文介绍了游戏服务器中逻辑服务器如何处理客户端请求,并通过网关转发给DB服务器,以及DB服务器异步返回数据到逻辑服务器的过程。主要涉及消息的处理、用户句柄的使用以及异步响应队列的处理,确保数据正确地从数据服务器回传到客户端。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

客户端发送消息到逻辑服务器的网关,再转发消息到db服务器,接着异步返回到逻辑服务器,再返回到客户端。


本文内容:

1、客户端到逻辑服务器的请求消息

2、从数据服务器返回到逻辑服务器的响应

 

1、客户端到逻辑服务器的请求消息

接收处理线程的例行函数

void* ExecSockDataMgr::RecvDataProcessRoutine(ExecSockDataMgr *pRunData)

{

......

//处理客户端发送的数据包

pRunData->ProcessUserRecvPacket( pSession, pPacket->getOffsetPtr(), (int)pPacket->getAvaliableLength() );

......

}


VOID ExecSockDataMgr::ProcessUserRecvPacket(PRUNGATEUSERSESSION pSession, char *pBuffer, int nBufferSize)
{
......//检查包头校验码和消息长度
DispatchUserRecvPacket(pSession, pSession->RecvBuf.lpBuffer + sizeof(*pPackHdr), pPackHdr->wPacketSize);
......
}


网关的消息请求

VOID CLogicGate::DispatchUserRecvPacket(PRUNGATEUSERSESSION pSession, char *pBuffer, uint32 nBufferSize)
{

......

case common::NetCmd::cQueryCharList:
{
if (pSession->btUserState != eGUSSelChar)
return;
HandleUserQueryChar(pSession);
}
break;

......

}

派送消息到逻辑服务器的db连接线程

VOID CLogicGate::HandleUserQueryChar(PRUNGATEUSERSESSION pSession)
{
common::SERVERUSERHANDLE UsrHdl;//服务器间通信的用户句柄
UsrHdl.llSocket = pSession->nSocket;
UsrHdl.wUserIndex = pSession->nIndex;
UsrHdl.nVerify = pSession->nVerifyIdx;
UsrHdl.wGateIndex = m_nGateIndex;

//派送到db线程的发送请求队列
g_DBManager->requestQueryChar(&UsrHdl, pSession->nAccountId);
}

其中:

 服务器之间通信数据包中传递的用户句柄

* 如:客户端在逻辑服务器查询角色、创建角色等操作需要由
* 逻辑服务器转发给DB服务器,未能使逻辑服务器在DB服务器
* 返回数据后知晓是返回给那个客户端的消息,逻辑服务器会在
* 通信数据包中包含客户端句柄,DB服务器也会在返回的数据包
* 中返回此句柄。
struct ServerUserHandle
{
unsigned long long llSocket;//socket
unsigned short wGateIndex;//网关索引
unsigned short wUserIndex;//网关用户索引
int nVerify;//校验码
};

typedef ServerUserHandle SERVERUSERHANDLE, *PSERVERUSERHANDLE;


提交数据包到数据发送队列

void CDBManager::requestQueryChar(common::SERVERUSERHANDLE *pUserHandle, int nAccountId)
{
CDataPacket &packet = AllocProtoPacket(common::DBType::dcQueryCharList);
packet << *pUserHandle;
packet << nAccountId;
FlushProtoPacket(packet);
}


2、从数据服务器返回到逻辑服务器的响应

数据服务器和逻辑服务器异步过程返回的异步数据类型 

struct SynergyData
{
common::SERVERUSERHANDLE userHandle;
enum OPType
{
aorLogin = 1,//登陆返回
aorQueryCharList,//查询角色列表返回
aorCreateChar,//创建角色返回
aorDeleteChar,//删除角色返回
aorEnterGame,//进入游戏返回
}opType;
union
{
struct {
int nErrorCode; 
int nUserId;
}login;//登录返回
struct {
int nCharCount;
CPoolDataPacket *pPacket;
}querychar;//查询角色列表返回
struct {
int nErrorCode;
CPoolDataPacket *pPacket;
}createchar;//创建角色返回
struct {
int nErrorCode;
}deletechar;//删除角色返回
struct {
int nErrorCode;
}enterGame;//进入游戏返回
};
};

(1)db连接线程处理返回的消息

服务器之间的连接线程的消息队列 派送的消息包

//逻辑服务器的db线程派送消息

void CDBManager::DispatchRecvPacket(CDataPacketReader &inPacket)
{
common::NetPacketMessage msg(0);
inPacket >> msg;

switch(msg.wMsg)
{
......
case common::DBType::dsSendCharList:
HandleQueryCharListRet(inPacket);
break;

...

}

获取对应的网关来派送

void CDBManager::HandleQueryCharListRet(CDataPacketReader &inPacket)
{
common::SERVERUSERHANDLE userHandle;
int nAccountId, nCharCount;
inPacket >> userHandle;
inPacket >> nAccountId;
inPacket >> nCharCount;

CLogicGate *pGate = g_GateManager->getGate(userHandle.wGateIndex);
if (pGate)
{
CPoolDataPacket *pRetPack = m_DataPacketPool.allocPacket();
pRetPack->writeBuf(inPacket.getOffsetPtr(), inPacket.getAvaliableLength());
pGate->resultUserQueryCharList(&userHandle, nCharCount, pRetPack);
}
}


//添加到异步响应队列 

void CLogicGateSynergy::resultUserQueryCharList(const common::SERVERUSERHANDLE *pUserHandle, int nCharCount, CPoolDataPacket *pPacket)
{
SynergyData data;

data.userHandle = *pUserHandle;
data.opType = SynergyData::aorQueryCharList;
data.querychar.nCharCount = nCharCount;
data.querychar.pPacket = pPacket;
m_SynergyDataList.append(data);
}


(2)数据接收处理线程处理异步返回的消息

在数据接收处理线程的循环里处理db连接线程的发来的异步响应消息

void* ExecSockDataMgr::RecvDataProcessRoutine(ExecSockDataMgr *pRunData)
{
......

while ( !pRunData->m_boStoping )
{
......
//调用例行执行函数
pRunData->OnRecvThreadSingleRun(dwProcStartTick);

......

}

VOID CLogicGate::OnRecvThreadSingleRun(TICKCOUNT dwCurrTick)
{
super::OnRecvThreadSingleRun(dwCurrTick);
ProcessSynergyList();
}

处理异步数据队列

void CLogicGateSynergy::ProcessSynergyList()
{
m_SynergyDataList.flush();//异步消息队列

INT_PTR i, nCount = m_SynergyDataList.count();
for (i=0; i<nCount; ++i)
{
HandleSynergyData(&m_SynergyDataList[i]);
}
m_SynergyDataList.clear();
}

处理异步数据

void CLogicGate::HandleSynergyData(SynergyData *pData)
{
DispatchSynergyData(pData);
DestroySynergyData(pData);
}

网关提交消息到网关的发送队列,准备发送消息到客户端

void CLogicGate::DispatchSynergyData(SynergyData *pData)
{
PRUNGATEUSERSESSION pSession;

//检查用户有效性,确保用户未过期
if (pData->userHandle.wUserIndex >= m_SessionList.count())
return;
pSession = m_SessionList[pData->userHandle.wUserIndex];
if (!pSession || pSession->nSocket != (int)pData->userHandle.llSocket\
|| pSession->nVerifyIdx != pData->userHandle.nVerify)
return;

switch(pData->opType)
{
case SynergyData::aorQueryCharList:
{
CGateSendPacket &packet = AllocSendPacket(pSession->nIndex);
packet.writeCmd(common::SystemId::sysLogin, common::NetCmd::sSendCharList);
packet << pData->querychar.nCharCount;
packet.writeBuf(pData->querychar.pPacket->getMemoryPtr(), pData->querychar.pPacket->getLength());
pData->createchar.pPacket->freeBack();
packet.flush();
}
break;

......
}
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值