消息缓冲区
每个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>
“`