28_分离消息缓冲区

消息缓冲区

每个cellclient都有自己的发送缓冲区和接收缓冲区,这两个缓冲区的功能是相近的,为了容纳每个客户端发送过来的数据,进行处理。

CELLBuffer.hpp

#ifndef _CELL_BUFFER_HPP_
#define _CELL_BUFFER_HPP_
#include"CELL.hpp"
class CELLBuffer
{
public:
    CELLBuffer(int nSize = 8192)
    {
        _nSize = nSize;
        _pBuff = new char[_nSize];
    }

    char* data()
    {
        return _pBuff;
    }

    bool push(const char* pData, int nLen)    //push 为了 发送缓冲区 服务
    {
        if (_nLast + nLen <= _nSize)
        {
            //将要发送的数据 拷贝到发送缓冲区尾部
            memcpy(_pBuff + _nLast, pData, nLen);
            //计算数据尾部位置
            _nLast += nLen;

            if (_nLast == SEND_BUFF_SZIE)
            {
                ++_fullCount;
            }

            return true;
        }
        else {
            ++_fullCount;
        }

        return false;
    }

    void pop(int nLen)
    {
        int n = _nLast - nLen;
        if (n > 0)
        {
            memcpy(_pBuff, _pBuff + nLen, n);
        }
        _nLast = n;
        if (_fullCount > 0)
            --_fullCount;
    }

    bool hasMsg()  
    {
        //判断消息缓冲区的数据长度大于消息头netmsg_DataHeader长度
        if (_nLast >= sizeof(netmsg_DataHeader))
        {
            //这时就可以知道当前消息的长度
            netmsg_DataHeader* header = (netmsg_DataHeader*)_pBuff;
            //判断消息缓冲区的数据长度大于消息长度
            return _nLast >= header->dataLength;
        }
        return false;
    }

    int write2socket(SOCKET sockfd)
    {
        int ret = 0;
        //缓冲区有数据
        if (_nLast > 0 && INVALID_SOCKET != sockfd)
        {
            //发送数据
            ret = send(sockfd, _pBuff, _nLast, 0);
            //数据尾部位置清零
            _nLast = 0;
            //
            _fullCount = 0;
        }
        return ret;
    }

    int read4socket(SOCKET sockfd)
    {
        if (_nSize - _nLast > 0)
        {
            //接收客户端数据
            char* szRecv = _pBuff + _nLast;
            int nLen = (int)recv(sockfd, szRecv, _nSize - _nLast, 0);
            //printf("nLen=%d\n", nLen);
            if (nLen <= 0)
            {
                return nLen;
            }
            //消息缓冲区的数据尾部位置后移
            _nLast += nLen;
            return nLen;
        }
        return 0;
    }

    ~CELLBuffer()
    {
        if (_pBuff)
        {
            delete[] _pBuff;
            _pBuff = nullptr;
        }
    }
protected:

private:
    //第二缓冲区 发送缓冲区
    char* _pBuff = nullptr;
    //可以用链表或队列来管理缓冲数据块
    //list<char*> _pBuffList;
    //缓冲区的数据尾部位置,已有数据长度
    int _nLast = 0;
    //缓冲区总的空间大小,字节长度
    int _nSize = 0;
    //缓冲区写满次数计数
    int _fullCount = 0;
};

#endif

Cellclient.cpp的改变

#ifndef _CELLClient_HPP_
#define _CELLClient_HPP_

#include"CELL.hpp"
#include"CELLBuffer.hpp"

//客户端心跳检测死亡计时时间
#define CLIENT_HREAT_DEAD_TIME 60000
//在间隔指定时间后
//把发送缓冲区内缓存的消息数据发送给客户端
#define CLIENT_SEND_BUFF_TIME 200
//客户端数据类型
class CELLClient
{
public:
    CELLClient(SOCKET sockfd = INVALID_SOCKET):
        _sendBuff(SEND_BUFF_SZIE),
        _recvBuff(RECV_BUFF_SZIE)
    {
        static int n = 1;
        id = n++;
        _sockfd = sockfd;

        resetDTHeart();
        resetDTSend();
    }

    int RecvData()
    {
        return _recvBuff.read4socket(_sockfd);
    }

    bool hasMsg()
    {
        return _recvBuff.hasMsg();
    }

    netmsg_DataHeader* front_msg()
    {
        return (netmsg_DataHeader*)_recvBuff.data();
    }

    void pop_front_msg()
    {
        if(hasMsg())
            _recvBuff.pop(front_msg()->dataLength);
    }

    //立即将发送缓冲区的数据发送给客户端
    int SendDataReal()
    {
        resetDTSend();
        return _sendBuff.write2socket(_sockfd);
    }

    //缓冲区的控制根据业务需求的差异而调整
    //发送数据
    int SendData(netmsg_DataHeader* header)
    {
        if (_sendBuff.push((const char*)header, header->dataLength))
        {
            return header->dataLength;
        }
        return SOCKET_ERROR;
    }

    void resetDTHeart()
    {
        _dtHeart = 0;
    }

    void resetDTSend()
    {
        _dtSend = 0;
    }

    //心跳检测
    bool checkHeart(time_t dt)
    {
        _dtHeart += dt;
        if (_dtHeart >= CLIENT_HREAT_DEAD_TIME)
        {
            printf("checkHeart dead:s=%d,time=%ld\n",_sockfd, _dtHeart);
            return true;
        }
        return false;
    }

    //定时发送消息检测
    bool checkSend(time_t dt)
    {
        _dtSend += dt;
        if (_dtSend >= CLIENT_SEND_BUFF_TIME)
        {
            //printf("checkSend:s=%d,time=%d\n", _sockfd, _dtSend);
            //立即将发送缓冲区的数据发送出去
            SendDataReal();
            //重置发送计时
            resetDTSend();
            return true;
        }
        return false;
    }
private:
    //第二缓冲区 接收消息缓冲区
    CELLBuffer _recvBuff;
    //发送缓冲区
    CELLBuffer _sendBuff;
};

#endif // !_CELLClient_HPP_

Cellserver.cpp的改变

“`c++
#ifndef _CELL_SERVER_HPP_
#define _CELL_SERVER_HPP_

#include"CELL.hpp"
#include"INetEvent.hpp"
#include"CELLClient.hpp"
#include"CELLSemaphore.hpp"

#include<vector>
#include<map>

//网络消息接收处理服务类
class CELLServer
{
public:

<pre><code>//接收数据 处理粘包 拆分包
int RecvData(CELLClient* pClient)
{
//接收客户端数据
int nLen = pClient->RecvData();
if (nLen <= 0)
{
return -1;
}
//触发<接收到网络数据>事件
_pNetEvent->OnNetRecv(pClient);
//循环 判断是否有消息需要处理
while (pClient->hasMsg())
{
//处理网络消息
OnNetMsg(pClient, pClient->front_msg());
//移除消息队列(缓冲区)最前的一条数据
pClient->pop_front_msg();
}
return 0;
}
</code></pre>

};

#endif // !<em>CELL_SERVER_HPP</em>

“`

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top