zoukankan      html  css  js  c++  java
  • GS LiveMgr心跳管理类

    struct LiveMgr
    {
    private:
        int                            m_nCount;            ///< 管理数量
        std::vector<int>            m_vecChannels;        ///< 所有channel
        std::shared_ptr<I_Timer>    m_spTimer;            ///< 定时器
     public:
         std::function<void(int channel)> m_fnTimeOutDisconnect;
        void Init(int nMaxGcNumb);
        bool IsLive(int nChannelId)
        {
            return !!(m_vecChannels[nChannelId]);
        }
        void OnLive(int nChannelId)
        {
            m_vecChannels[nChannelId] = GetTickCount();
        }
        void Add(int nChannelId)
        {
            m_nCount++;
             m_vecChannels[nChannelId] = GetTickCount();
        }
        void Remove(int nChannelId)
        {
            m_nCount--;
            m_vecChannels[nChannelId] = 0;
        }
        void Check();
        int GetLinks()
        {
            return m_nCount;
        }
        
    };
    这个是心跳管理类
    GS初始化的时候
    m_LiveMgr.m_fnTimeOutDisconnect = std::bind(&GameServer::TimeOutDisconnect, this, ph::_1);
    m_LiveMgr.Init(GetMaxGcNumb());
    
    void LiveMgr::Init(int max_gc_numb)
    {
        ///创建内部定时检查的定时器,5s执行一次,不过为了现在方便把定时器关闭了
        m_spTimer.reset(GetPlug(TimerFactory)->createTimer());
        m_spTimer->regTimer(std::bind(&LiveMgr::Check, this));
        m_spTimer->setInterval(5 * 1000);
        //为调试先关掉
        //m_timer->start();
    
        m_vecChannels.resize(max_gc_numb);//m_vecChannels保存的所有channel最新的包跟新时间,注意这个默认初始化为0
        m_nCount = 0;
    }
    那这个是什么时候更新的呢
    if(rPkt.is_data)
    {
        if(!rPkt.data)
            return false;
    
        GameChannel* pGC = m_vecChannel[rPkt.channel_id];
        if(pGC)
            pGC->OnReceiveData(rPkt.data, rPkt.size);
    
        m_LiveMgr.OnLive(rPkt.channel_id);//看来这个是每接收一个包的时候将channel的最新时间更新一下
    }
    void OnLive(int nChannelId)
    {
        m_vecChannels[nChannelId] = GetTickCount();
    }
    看看这个5s定时回调的函数做了什么
    void LiveMgr::Check()
    {
        size_t uNow = GetTickCount();
        for (size_t i = 0; i < m_vecChannels.size(); ++i)//遍历所有channel,这个效率???
        {
            size_t uLastTick = m_vecChannels[i];
            //uLastTick为0表示没有连接,这句就说明连接了并且15没有接收到数据了,就认为其断线了,会走下线处理的
            //想当时测试的时候把网线拔了,此时libevent是不能收到事件的,GS他的连接还是在上面的,如果把定时器打开,15秒后会将其删除的
            if(uLastTick && uNow - uLastTick > 15 * 1000)
            {
                m_fnTimeOutDisconnect(i);
                Remove(i);//需要将m_vecChannels对应位置赋值为0,表示没有连接,刚才我还在想这边把socket关闭了,不会受到断开通知,这里处理了就对了
            }
        }
    }
    //看看这个function做了什么
    做相应的下线处理,并关闭网络层的socket
    void GameServer::TimeOutDisconnect(int nChannelId)
    {
        try
        {
            GameChannel* pGC = m_vecChannel[nChannelId];
            pGC->OnDisconnect();//玩家下线处理,回头看玩家下线在详看
            if(!pGC->m_pMap)
            {
                //PushFreeQueue(pGC);
                //m_vecChannel[nChannelId] = NULL;
                AutoFreeGC(pGC);
            }
            m_spDataLayer->Close(nChannelId);//这个属于主动断开客户端的连接,libevent那边调用close_channel放入下线队列中,主线程去关闭socket,这个过程应该很清楚了
        }
        catch (...)
        {
            DWORD e = GetLastError();
            Plug::PlugMessageBox(L"m_spTCPServer->close_channel异常了啊!");
        }
    }
    //我在想,当时踢玩家下线,是因为那边放入释放队列,60s之后关闭socket,此时客户端收到通知
    但对于拔网线,那客户端好像也能收到通知,服务端心跳检测关闭时永远都不能收到通知的,那客户端怎么会收到通知的呢,来试验一下
  • 相关阅读:
    Qt操作xml文件(增删改功能)
    Qt解析xml
    Qt中使用DOM解析XML文件或者字符串二(实例)
    Qt中使用DOM解析XML文件或者字符串(实例)
    QThread 实用技巧、误区----但文档中没有提到
    事件循环与线程 二
    事件循环与线程 一
    第一讲 递归
    Ubuntu 建立桌面快捷方式
    Codeforces554B:Ohana Cleans Up
  • 原文地址:https://www.cnblogs.com/zzyoucan/p/4116633.html
Copyright © 2011-2022 走看看