http://blog.csdn.net/soft2967/article/details/8744092
1.什么是环形缓冲区?
环形缓冲区一般是一段连续的buffer空间,空间可以是new或者使用vector<char>分配,这些空间对计算机来说是线性的,但我们在读取或者写入的时候需要%来计算读写的位置,
这样就抽象成环了。
2.什么时候用环形缓冲区
game的后台通常是几个程序来组成一个集群。这样几个后台进程必然需要通信。
比如下面一个简单的结构
client--------- 接入层svr------logicsvr---------dbsvr
这样接入层在收到客户端数据包后需要把数据在发送给logicsvr,这样2个进程就需要通信 。进程间通信有多种方式,比如共享内存,socket方式等。
假如使用共享内存,那么2个进程如果读写而且还不用加锁(这里的读写是 一个只会去读数据,另一个只会去写数据)这个时候使用环形缓冲区就比较适合
下面是一个简单的实现
- #pragma once
- #include <vector>
- #define QUEUERESERVELENGTH 8 //保留8个字节不用
- #define MAX_BUF_LEN 0x7FF0
- class CCricleBuffer
- {
- public:
- CCricleBuffer(unsigned int MaxLen);
- ~CCricleBuffer(void);
- //缓存区是否已满
- bool IsFull();
- //写入数据
- bool AppendBuffer(char* pBuffer, short len);
- //获得一个完整的packet
- bool GetPacket(char* pBuffer, short& TranLen, short MaxLen);
- private:
- //获得缓存区剩余大小
- unsigned int GetRemain();
- private:
- std::vector<char> m_CricleBuf;
- unsigned int m_Len;
- unsigned int m_ActiveLen;
- unsigned int m_ReadPos;
- unsigned int m_WritePos;
- };
- #include "StdAfx.h"
- #include "CricleBuffer.h"
- CCricleBuffer::CCricleBuffer(unsigned int MaxLen)
- {
- m_Len = MaxLen;
- m_ActiveLen = MaxLen - QUEUERESERVELENGTH;
- m_ReadPos = 0;
- m_WritePos = 0;
- m_CricleBuf.resize(MaxLen);
- }
- CCricleBuffer::~CCricleBuffer(void)
- {
- }
- unsigned int CCricleBuffer::GetRemain()
- {
- unsigned int RemainLen = 0;
- if (m_ReadPos == m_WritePos)
- {
- RemainLen = m_Len;
- }
- else if (m_WritePos < m_ReadPos)
- {
- RemainLen = m_ReadPos - m_WritePos;
- }
- else
- {
- RemainLen = (m_Len - m_WritePos) + m_ReadPos;
- }
- return RemainLen;
- }
- bool CCricleBuffer::IsFull()
- {
- unsigned int RemainLen = GetRemain();
- if (RemainLen - QUEUERESERVELENGTH > 0)
- {
- return false;
- }
- return true;
- }
- bool CCricleBuffer::AppendBuffer(char* pBuffer, short len)
- {
- if (pBuffer == NULL || len == 0)
- {
- //print log
- return false;
- }
- if (m_ReadPos < 0 || m_ReadPos > m_Len ||
- m_WritePos <0 || m_WritePos > m_Len)
- {
- //print log
- return false;
- }
- if (IsFull())
- {
- //print log
- return false;
- }
- unsigned int RemainLen = GetRemain() - QUEUERESERVELENGTH;
- if (len + sizeof(len) > RemainLen)
- {
- //print log
- return false;
- }
- char* pDest = (char*)&len;
- int shortlen = sizeof(len);
- for (int i = 0; i < shortlen; ++i)
- {
- m_CricleBuf[m_WritePos] = pDest[i];
- m_WritePos = (m_WritePos + 1) % m_Len;
- }
- if (m_WritePos < m_ReadPos)
- {
- memcpy((void*)&m_CricleBuf[m_WritePos],pBuffer,len);
- }
- else
- {
- if (m_Len - m_WritePos > len)
- {
- memcpy((void*)&m_CricleBuf[m_WritePos],(const void*)pBuffer,len);
- }
- else
- {
- //需要做2次copy
- unsigned int half = m_Len - m_WritePos;
- memcpy((void*)&m_CricleBuf[m_WritePos],(const void*)pBuffer,half);
- memcpy((void*)&m_CricleBuf[0],(const void*)pBuffer[half], len - half);
- }
- }
- m_WritePos = (m_WritePos + m_Len) % m_Len;
- return true;
- }
- //pBuffer 输出缓存区瘦地址
- //TranLen 实际的读取buffer长度
- bool CCricleBuffer::GetPacket(char* pBuffer, short& TranLen, short MaxLen)
- {
- if (NULL== pBuffer || MaxLen > MAX_BUF_LEN)
- {
- //print log
- return false;
- }
- if (m_ReadPos < 0 || m_ReadPos > m_Len ||
- m_WritePos <0 || m_WritePos > m_Len)
- {
- //print log
- return false;
- }
- if (IsFull())
- {
- //print log
- return false;
- }
- unsigned int RemainLen = GetRemain() - QUEUERESERVELENGTH;
- if (RemainLen <= sizeof(short))
- {
- //print log
- return false;
- }
- //读short长度,为后面一个完整的packet的长度
- unsigned int shortlen = sizeof(short);
- char* buff = (char*)&TranLen;
- for (int i = 0;i < shortlen; ++i)
- {
- buff[i] = m_CricleBuf[m_ReadPos];
- m_ReadPos = (m_ReadPos + 1) % m_Len;
- }
- //判断后面的长度是否有一个完整的packet
- if (RemainLen - sizeof(short) < TranLen || TranLen <=0)
- {
- //print log
- return false;
- }
- if (m_ReadPos < m_WritePos)
- {
- memcpy((void*)pBuffer,(const void*)&m_CricleBuf[m_ReadPos],TranLen);
- }
- else
- {
- unsigned int half = m_Len - m_ReadPos;
- if (half > TranLen)
- {
- memcpy((void*)pBuffer,(const void*)&m_CricleBuf[m_ReadPos],TranLen);
- }
- else
- {
- memcpy((void*)pBuffer,(const void*)&m_CricleBuf[m_ReadPos],half);
- memcpy((void*)pBuffer[half],(const void*)&m_CricleBuf[0],TranLen-half);
- }
- }
- m_ReadPos = (m_ReadPos + TranLen) % m_Len;
- return true;
- }
浙公网安备 33010602011771号