void CClientMgr::SendMsg(CClient *cl, google::protobuf::Message &pMsg, int32 maintype, int32 subtype) { assert(cl != nullptr); MessagePack pk; pk.Pack(&pMsg, maintype, subtype); cl->SendMsg(&pk); }
void ServiceCore::OperateAM(const MessagePack &rstMPK) { switch(rstMPK.Type()){ case MPK_BADCHANNEL: { On_MPK_BADCHANNEL(rstMPK); break; } case MPK_METRONOME: { On_MPK_METRONOME(rstMPK); break; } case MPK_ADDCHAROBJECT: { On_MPK_ADDCHAROBJECT(rstMPK); break; } case MPK_TRYMAPSWITCH: { On_MPK_TRYMAPSWITCH(rstMPK); break; } case MPK_NETPACKAGE: { On_MPK_NETPACKAGE(rstMPK); break; } case MPK_QUERYMAPLIST: { On_MPK_QUERYMAPLIST(rstMPK); break; } case MPK_QUERYCOCOUNT: { On_MPK_QUERYCOCOUNT(rstMPK); break; } case MPK_QUERYMAPUID: { On_MPK_QUERYMAPUID(rstMPK); break; } default: { extern MonoServer *g_MonoServer; g_MonoServer->AddLog(LOGTYPE_WARNING, "Unsupported message: %s", rstMPK.Name()); break; } } }
static void back_dofunction(lxnet::Socketer *sock) { MessagePack *pack; char commandstr[32]; Msg *pmsg = sock->GetMsg(); if (!pmsg) return; pack = (MessagePack *)pmsg; pack->Begin(); pack->GetString(commandstr, sizeof(commandstr)); commandstr[sizeof(commandstr) - 1] = 0; ProcessCommand(sock, commandstr); }
void ServiceCore::On_MPK_QUERYMAPUID(const MessagePack &rstMPK) { AMQueryMapUID stAMQMUID; std::memcpy(&stAMQMUID, rstMPK.Data(), sizeof(stAMQMUID)); if(auto pMap = RetrieveMap(stAMQMUID.MapID)){ AMUID stAMUID; std::memset(&stAMUID, 0, sizeof(stAMUID)); stAMUID.UID = pMap->UID(); m_ActorPod->Forward(rstMPK.From(), {MPK_UID, stAMUID}, rstMPK.ID()); }else{ m_ActorPod->Forward(rstMPK.From(), MPK_ERROR, rstMPK.ID()); } }
void ServiceCore::On_MPK_ADDCHAROBJECT(const MessagePack &rstMPK) { AMAddCharObject stAMACO; std::memcpy(&stAMACO, rstMPK.Data(), sizeof(stAMACO)); if(stAMACO.Common.MapID){ if(auto pMap = RetrieveMap(stAMACO.Common.MapID)){ if(false || stAMACO.Common.Random || pMap->In(stAMACO.Common.MapID, stAMACO.Common.X, stAMACO.Common.Y)){ m_ActorPod->Forward(pMap->UID(), {MPK_ADDCHAROBJECT, stAMACO}, [this, stAMACO, rstMPK](const MessagePack &rstRMPK) { switch(rstRMPK.Type()){ case MPK_OK: { m_ActorPod->Forward(rstMPK.From(), MPK_OK, rstMPK.ID()); break; } default: { m_ActorPod->Forward(rstMPK.From(), MPK_ERROR, rstMPK.ID()); break; } } }); return; } } } // invalid location info, return error directly m_ActorPod->Forward(rstMPK.From(), MPK_ERROR, rstMPK.ID()); }
void ServiceCore::On_MPK_QUERYMAPLIST(const MessagePack &rstMPK) { AMMapList stAMML; std::memset(&stAMML, 0, sizeof(stAMML)); size_t nIndex = 0; for(auto pMap: m_MapList){ if(pMap.second && pMap.second->ID()){ if(nIndex < (sizeof(stAMML.MapList) / sizeof(stAMML.MapList[0]))){ stAMML.MapList[nIndex++] = pMap.second->ID(); }else{ extern MonoServer *g_MonoServer; g_MonoServer->AddLog(LOGTYPE_FATAL, "Need larger map list size in AMMapList"); g_MonoServer->Restart(); } } } m_ActorPod->Forward(rstMPK.From(), {MPK_MAPLIST, stAMML}, rstMPK.ID()); }
void ServiceCore::On_MPK_BADCHANNEL(const MessagePack &rstMPK) { // channel may go down before bind to one actor // then stop it here AMBadChannel stAMBC; std::memcpy(&stAMBC, rstMPK.Data(), sizeof(stAMBC)); extern NetDriver *g_NetDriver; g_NetDriver->Shutdown(stAMBC.ChannID, false); }
void ServiceCore::On_MPK_TRYMAPSWITCH(const MessagePack &rstMPK) { AMTryMapSwitch stAMTMS; std::memcpy(&stAMTMS, rstMPK.Data(), sizeof(stAMTMS)); if(stAMTMS.MapID){ if(auto pMap = RetrieveMap(stAMTMS.MapID)){ m_ActorPod->Forward(pMap->UID(), {MPK_TRYMAPSWITCH, stAMTMS}); } } }
void CClientMgr::SendMsg(int32 clientid, google::protobuf::Message &pMsg, int32 maintype, int32 subtype) { if (clientid > 0) { CClient *cl = FindClientByClientID(clientid); if (cl) { MessagePack pk; pk.Pack(&pMsg, maintype, subtype); cl->SendMsg(&pk); } } else { MessagePack pk; pk.Pack(&pMsg, maintype, subtype); std::list<CClient*>::iterator _Iter = m_ClientList.begin(); for (; _Iter != m_ClientList.end(); ++_Iter) (*_Iter)->SendMsg(&pk); } }
// ServiceCore accepts net packages from *many* sessions and based on it to create // the player object for a one to one map // // So servicecore <-> session is 1 to N, means we have to put put pointer of session // in the net package otherwise we can't find the session even we have session's // address, session is a sync-driver, even we have it's address we can't find it // void ServiceCore::On_MPK_NETPACKAGE(const MessagePack &rstMPK) { AMNetPackage stAMNP; std::memcpy(&stAMNP, rstMPK.Data(), sizeof(AMNetPackage)); uint8_t *pDataBuf = nullptr; if(stAMNP.DataLen){ if(stAMNP.Data){ pDataBuf = stAMNP.Data; }else{ pDataBuf = stAMNP.DataBuf; } } OperateNet(stAMNP.ChannID, stAMNP.Type, pDataBuf, stAMNP.DataLen); if(stAMNP.Data){ delete [] stAMNP.Data; } }
void CBaseObj::SendRefMsg(Msg &pMsg) { assert(m_GateIDMax < gateinfo_count); for (int i = m_GateIDMin; i <= m_GateIDMax; ++i) { gateinfo[i]->Reset(); } static bool bNeeSendMsg = false; static msgtail tail; std::unordered_map<uint32, CBaseObj *> *playerlist = GetAoiList(); std::unordered_map<uint32, CBaseObj *>::iterator iter = playerlist->begin(); for (; iter != playerlist->end(); ++iter) { if (iter->second->IsPlayer()) { CPlayer * p = (CPlayer *)iter->second; if (FuncUti::isValidCret(p)) { int32 gateid = p->GetGateID(); if (gateid >= 0 && gateid < gateinfo_count) { if (gateid > m_GateIDMax) { m_GateIDMax = gateid; } else if (gateid < m_GateIDMin) { m_GateIDMin = gateid; } if (gateinfo[gateid]->gate == nullptr) { gateinfo[gateid]->gate = p->GetGateInfo(); } gateinfo[gateid]->nClientId[gateinfo[gateid]->nCount] = p->GetClientID(); gateinfo[gateid]->nCount += 1; } } } } static bool bIsPlayer = false; bIsPlayer = IsPlayer(); if (bNeeSendMsg || bIsPlayer) { if (bIsPlayer) { CPlayer *p = (CPlayer *)this; int32 gateid = p->GetGateID(); if (gateid >= 0 && gateid < gateinfo_count) { if (gateid > m_GateIDMax) { m_GateIDMax = gateid; } else if (gateid < m_GateIDMin) { m_GateIDMin = gateid; } if (gateinfo[gateid]->gate == nullptr) { gateinfo[gateid]->gate = p->GetGateInfo(); } gateinfo[gateid]->nClientId[gateinfo[gateid]->nCount] = p->GetClientID(); gateinfo[gateid]->nCount += 1; } } bNeeSendMsg = false; MessagePack pkmain; pkmain.PushInt32(pMsg.GetLength()); pkmain.PushBlock(&pMsg, pMsg.GetLength()); int32 pkmainlen = pkmain.GetLength(); for (int i = m_GateIDMin; i < m_GateIDMax; ++i) { if (gateinfo[i]->nCount > 0) { tail.id = 0; for (int j = 0; j < gateinfo[i]->nCount; ++j) { pkmain.PushInt32(gateinfo[i]->nClientId[j]); --tail.id; } GameGatewayMgr.SendMsg(gateinfo[i]->gate, pkmain, &tail, sizeof(tail)); pkmain.SetLength(pkmainlen); pkmain.m_index = pkmainlen - (int32)sizeof(Msg); } } } }
void ServiceCore::On_MPK_QUERYCOCOUNT(const MessagePack &rstMPK) { AMQueryCOCount stAMQCOC; std::memcpy(&stAMQCOC, rstMPK.Data(), sizeof(stAMQCOC)); int nCheckCount = 0; if(stAMQCOC.MapID){ if(m_MapList.find(stAMQCOC.MapID) == m_MapList.end()){ nCheckCount = 0; }else{ nCheckCount = 1; } }else{ nCheckCount = (int)(m_MapList.size()); } switch(nCheckCount){ case 0: { m_ActorPod->Forward(rstMPK.From(), MPK_ERROR, rstMPK.ID()); return; } case 1: { if(auto pMap = (stAMQCOC.MapID ? m_MapList[stAMQCOC.MapID] : m_MapList.begin()->second)){ m_ActorPod->Forward(pMap->UID(), {MPK_QUERYCOCOUNT, stAMQCOC}, [this, rstMPK](const MessagePack &rstRMPK) { switch(rstRMPK.Type()){ case MPK_COCOUNT: { m_ActorPod->Forward(rstMPK.From(), {MPK_COCOUNT, rstRMPK.Data(), rstRMPK.DataLen()}, rstMPK.ID()); return; } case MPK_ERROR: default: { m_ActorPod->Forward(rstMPK.From(), MPK_ERROR, rstMPK.ID()); return; } } }); return; }else{ m_MapList.erase(stAMQCOC.MapID); m_ActorPod->Forward(rstMPK.From(), MPK_ERROR, rstMPK.ID()); return; } } default: { // difficult part // need send multiple query message and collect them // after all collected we need to return the sum, problem: // 1. share state // 2. error handle struct SharedState { bool Done; int CheckCount; int COCount; SharedState(int nCheckCount) : Done(false) , CheckCount(nCheckCount) , COCount(0) {} }; // current I don't have error handling // means if one query didn't get responded it will wait forever // to solve this issue, we can install an state hook but for simplity not now auto pSharedState = std::make_shared<SharedState>(nCheckCount); auto fnOnResp = [pSharedState, this, rstMPK](const MessagePack &rstRMPK) { switch(rstRMPK.Type()){ case MPK_COCOUNT: { if(pSharedState->Done){ // we get response but shared state shows ``done" // means more than one error has alreay happened before // do nothing }else{ // get one more valid response // need to check if we need to response to sender AMCOCount stAMCOC; std::memcpy(&stAMCOC, rstRMPK.Data(), sizeof(stAMCOC)); if(pSharedState->CheckCount == 1){ stAMCOC.Count += pSharedState->COCount; m_ActorPod->Forward(rstMPK.From(), {MPK_COCOUNT, stAMCOC}, rstMPK.ID()); }else{ pSharedState->CheckCount--; pSharedState->COCount += (int)(stAMCOC.Count); } } return; } case MPK_ERROR: default: { if(pSharedState->Done){ // we get response but shared state shows ``done" // means more than one error has alreay happened before // do nothing }else{ // get first error m_ActorPod->Forward(rstMPK.From(), MPK_ERROR, rstMPK.ID()); } return; } } }; for(auto p: m_MapList){ m_ActorPod->Forward(p.second->UID(), {MPK_QUERYCOCOUNT, stAMQCOC}, fnOnResp); } return; } } }
static void ProcessCommand(lxnet::Socketer *sock, const char *commandstr) { static char s_buf[32 * 1024]; short size = 0; MessagePack res; if (strcmp(commandstr, "help") == 0) { snprintf(s_buf, sizeof(s_buf) - 1, "help 帮助\nopenelapsed/closeelapsed 打开/关闭帧开销实时日志\ncurrentinfo 输出当前信息\nnetmeminfo 输出网络库内存使用情况\nallmeminfo 输出此程序内存池使用信息到文件\n"); size = static_cast<short>(strlen(s_buf)) + 1; s_buf[size] = 0; res.PushString(s_buf); sock->SendMsg(&res); } else if (strcmp(commandstr, "openelapsed") == 0) { g_elapsed_log_flag = true; snprintf(s_buf, sizeof(s_buf) - 1, "帧开销实时日志已打开"); size = static_cast<short>(strlen(s_buf)) + 1; s_buf[size] = 0; res.PushString(s_buf); sock->SendMsg(&res); } else if (strcmp(commandstr, "closeelapsed") == 0) { g_elapsed_log_flag = false; snprintf(s_buf, sizeof(s_buf) - 1, "帧开销实时日志已关闭"); size = static_cast<short>(strlen(s_buf)) + 1; s_buf[size] = 0; res.PushString(s_buf); sock->SendMsg(&res); } else if (strcmp(commandstr, "currentinfo") == 0) { size = 0; DBCenterConnect.GetCurrentInfo(&s_buf[size], sizeof(s_buf) - size - 1); size = static_cast<short>(strlen(s_buf)); DBCenterConnect.GetDataHandInfo(&s_buf[size], sizeof(s_buf) - size - 1); size = static_cast<short>(strlen(s_buf)); DBCache.GetCurrentInfo(&s_buf[size], sizeof(s_buf) - size - 1); s_buf[sizeof(s_buf) - 1] = 0; res.PushString(s_buf); sock->SendMsg(&res); } else if (strcmp(commandstr, "netmeminfo") == 0) { snprintf(s_buf, sizeof(s_buf) - 1, "%s", lxnet::net_get_memory_info(s_buf, sizeof(s_buf) - 1)); size = static_cast<short>(strlen(s_buf)) + 1; s_buf[size] = 0; res.PushString(s_buf); sock->SendMsg(&res); } else if (strcmp(commandstr, "allmeminfo") == 0) { sPoolInfo.writeinfotofile(); snprintf(s_buf, sizeof(s_buf) - 1, "所有内存信息已经写入到文件"); size = static_cast<short>(strlen(s_buf)) + 1; s_buf[size] = 0; res.PushString(s_buf); sock->SendMsg(&res); } else { res.PushString(commandstr); sock->SendMsg(&res); } }
int main() { if(!lxnet::net_init(512, 1, 1024*32, 100, 1, 4, 1)) { printf("init network error!\n"); system("pause"); return 0; } lxnet::Listener *list = lxnet::Listener::Create(); if (!list->Listen(30012, 10)) { printf("listen error\n"); } if (list) { MessagePack sendpack; MessagePack *recvpack; char neirong[1024*30]="a1234567"; //char recvneirong[32*1024]; int size = sizeof(neirong); sendpack.PushBlock(neirong, size); printf("listen succeed!\n"); lxnet::Socketer *newclient = NULL; while (1) { #ifdef WIN32 Sleep(100); #else usleep(100000); #endif lxnet::net_run(); if (!list->CanAccept()) continue; if (!(newclient = list->Accept())) continue; printf("accept succeed!\n"); //newclient->UseCompress(); //newclient->UseUncompress(); //newclient->UseDecrypt(); //newclient->UseEncrypt(); newclient->SetSendLimit(-1); //newclient->SetRecvLimit(16*1024); newclient->CheckRecv(); while(1) { recvpack = (MessagePack *)newclient->GetMsg(); if (recvpack) { //recvpack->Begin(); //recvpack->GetBlock(recvneirong, size); //if (memcmp(recvneirong, neirong, size) != 0) //{ // printf("data error!\n"); // system("pause"); //} newclient->SendMsg(&sendpack); newclient->CheckSend(); } else #ifdef WIN32 Sleep(0); #else sleep(0); #endif lxnet::net_run(); if (newclient->IsClose()) { system("pause"); lxnet::Socketer::Release(newclient); goto s_exit; } } } } else { printf("listen failed!\n"); } s_exit: system("pause"); printf("begin ... release..\n"); #ifdef WIN32 Sleep(1000); #else usleep(1000000); #endif lxnet::Listener::Release(list); lxnet::net_release(); system("pause"); return 0; }