玩家下线,之前一直感觉这个过程有点复杂
else if (stat == link_stat::link_disconnected || stat == link_stat::link_connect_failed )
{
GameChannel* pDisconnectGC = m_vecChannel[rPkt.channel_id];
if(pDisconnectGC)
{
//如果进入了地图,保存人物信息时会调用push_freeQueue + 滞空m_Channels[channel_id],
pDisconnectGC->OnDisconnect();//下线的一些收尾工作 //如果未进地图就下线,直接断开;不用保存角色详细数据,可直接放入释放队列中
if(!pDisconnectGC->m_pMap)
{
//PushFreeQueue(pDisconnectGC);
//m_vecChannel[rPkt.channel_id] = NULL;
AutoFreeGC(pDisconnectGC);
}
}
m_LiveMgr.Remove(rPkt.channel_id);//将livemgr的这个位置清零
}
下面一步一步看这个过程
bool GameChannel::OnDisconnect()
{
//m_isDisconnect = true;
OnOffLine();
return true;
} void GameChannel::OnOffLine()
{
switch (m_eGameState)
{
case eGameState_Login://登录状态
ClearLoginRcd();//清除登录状态:主要是删除已删除的角色,删除在线用户
break;
case eGameState_EnterMap://进入地图状态
ClearMapRcd();//从map下线,这个获取后面看
ClearLoginRcd();//清除登录状态
break;
case eGameState_InChangeMap:
//...正在切图就下线了,是不是该延时下线呢?
m_eGameState = eGameState_DelayDisconnect;
case eGameState_OnlyConnect: //未登陆,空连接
case eGameState_Disconnect: //已离线
return;
default:
break;
}
m_eGameState = eGameState_Disconnect;//将状态切换成离线状态
} void GameServer::AutoFreeGC(GameChannel* pGameChannel)
{
m_vecChannel[pGameChannel->m_nChannelId] = NULL;
//channel里面有个m_uDBGetAskRefCount,由于判断数据库是否有返回,加入数据库很慢的时候玩家下线你把这个内存释放了,等数据库返回的时候就访问了野指针
if (pGameChannel->IsNoDBAsk())//没有数据库访问,可以安全的删除指针了
{
delete pGameChannel;//删除玩家指针
pGameChannel = nullptr;
}
else
{
PushFreeQueue(pGameChannel);//如果还有数据库访问,就将其放到释放队列中延迟释放
}
} void GameServer::PushFreeQueue(GameChannel* gc)
{
FreeChannel fch;
fch.m_pGameChannel = gc;
fch.m_uTime = GetTickCount();
m_FreeQueue.push(fch);
} //那这个队列到底什么时候释放的呢?
在主线程里面初始化了一个定时器
void GameServer::InitTimer()
{
I_TimerFactory* pTimeFactory = NEW(TimerFactory);
SetPlug("TimerFactory", pTimeFactory);
m_FreeQueueTimer.reset(pTimeFactory->createTimer());
m_FreeQueueTimer->regTimer(std::bind(&GameServer::FreeQueueTimer, this));
m_FreeQueueTimer->setInterval( * );//(30 * 1000);
m_FreeQueueTimer->start();
} //之前出现过,函数回调的时候出现错误,当时就是这个问题回调的时候玩家已经下线了,channel已经删除了
/**
* 方案一:不直接释放,延迟1分钟,保证数据库不再返回时再释放。(数据库太忙情况不安全,停用)
* 方案二:不直接释放,看GC标志是否无数据请求。
*/
void GameServer::FreeQueueTimer()
{
if(!m_FreeQueue.size())
return ; int now = GetTickCount();
for (;;)//每次释放完或者到有不能释放的为止
{
if(!m_FreeQueue.size())
return ;
FreeChannel tmpFreeChannel = m_FreeQueue.front();
//if(now - tmpFreeChannel.m_uTime > 60 * 1000)
if (tmpFreeChannel.m_pGameChannel->IsNoDBAsk())//等到数据库没有访问了再释放
{
delete tmpFreeChannel.m_pGameChannel;
m_FreeQueue.pop();
}
else
{
break;
}
}
}

玩家下线(GS部分)的更多相关文章

  1. GS踢玩家下线功能

    GS踢玩家下线功能 //key:userId, val:nChannelId (当前在线用户) std::map<int, int> m_mapOnLineUserByUid; ///&l ...

  2. GS LiveMgr心跳管理类

    struct LiveMgr { private: int m_nCount; ///< 管理数量 std::vector<int> m_vecChannels; ///< 所 ...

  3. GS与网络打交道

    与网络打交道 在GS,GC,Share都与网络打交道,但还是GC最多 GC打交道过程 send_stat BaseChannel::SendCmdTry() { if (!m_queCmd.size( ...

  4. GS与数据库打交道

    GS与数据库打交道 link_stat stat = (link_stat)rPkt.size; if (stat == link_stat::link_connected) { GameChanne ...

  5. 再看GS线程

    再看GS线程 void GameServer::ProcessThreadTry() { ; packet rcvPkt; rcvPkt.data = * ]; //该事件工厂主要创建了两个定时器1. ...

  6. share干什么的

    share到底干什么的 //--------------------打开GameServer,share中加载------------------------- .加载nBodyID //玩家的nBo ...

  7. 项目分析(map复习)

    有段时间没看map里面的东西了,刚才看发现功能上增加了一些,在来复习了一次流程初始化每个map建立线程,这个线程有两个功能,1.处理GS发过来的包 2.驱动map里面的定时器GS发过来的包是存在m_g ...

  8. mmzb游戏事故分析

    最近一次线上更新,老项目挂了,遍地哀嚎,日活跃掉了好多,心痛... 这次维护时,SA为了缩减硬件资源,做了一次数据库迁移.给到开发手上的player db,只有一些索引数据,不带有任一玩家数据.玩家上 ...

  9. bigworld源码分析(3)——dbMgr分析

    dbMgr主要是玩家数据的读取和保存的,例如在bigworld源码分析(3)中,玩家在认证的时候,loginApp需要通过dbMgr来验证玩家数据是否合法,这就是针对玩家的账号数据进行查询.本篇中,我 ...

随机推荐

  1. 在Alfred添加自定义站内搜索

    1.Google的站内搜索和渣度的对比,懒得吐槽了 2.在Alfred添加自定义站内搜索步骤 Add Custome Search 把搜索某个关键词的url复制到里面,把url里的关键词替换成{que ...

  2. Django ModelChoiceField前台下拉菜单显示object的解决方法

    在网上找了好半天都没找到,在model中添加即可,不加的话显示就是object def __str__(self): return self.name

  3. black hack

    黑客技 关于在不知道系统的情况下 long long 的使用时 那么 #ifdef WIN32 #define LL "%I64d" #else #define LL " ...

  4. Linux(三) 一些命令

    系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...

  5. iOS7自定义back按钮和pop交互手势

    Clambake for iPhone有一个回退按钮在所有的导航条上.这是一个简单的没有文字箭头. 实现一个自定义按钮是简单的.类似这个设置controller 的navigationItem一个le ...

  6. iphone之判断屏幕方向

    有两种方法可以判断 1,程序刚开始运行的时候,不能获取当前方向.给你说几种方式,你试一下: 1. 可以在启动后0.01秒执行初始化的代码,这个时候就可以获取设备方向了. 2. 另外一种方式,借助状态栏 ...

  7. 【redis】存入redis的值,如果为null是否默认不被存入

    存入redis的值,如果为null是否默认不被存入

  8. centos7的时间同步机制:chrony使用

    配置时间同步方法如下: 1.安装chrony时间同步服务(系统默认安装) #yum install chrony 可以先查询一下是否有安装: [root@localhost etc]# rpm -qa ...

  9. EasyMvc入门教程-基本控件说明(3)时间线

    我们有时候经常看到如下的页面: 或者快递物流信息图标,那么利用EasyMvc如何实现呢?很简单,看下面的例子: @{ var data=new List<TimeLineItem>() { ...

  10. 控制面板的cpl程序列表

    控制面板的cpl程序列表 学习了:https://zhidao.baidu.com/question/2141898537654796628.html 最近用来sysdm.cpl: 辅助功能选项:ac ...