我们再处理网络数据包时,可能会将接受到的网络数据包放入缓冲区去做进一步的处理,这里我自己根据自己的需要用C++编写了一个环形缓冲区,实际上是用数组来进行模拟。
首先头文件“RingBuffer.h”如下:
#pragma once
//此处定义了缓冲区的大小
#define BUFFER_MAX_SIZE 1048576 // 1024 * 1024 1MB 1048576KB
class RingBuffer
{
public:
RingBuffer();
~RingBuffer();
public:
bool WriteRingBuffer(char* pSrc, int nByteSize);
bool ReadRingBuffer(char* pBuffer,int &nByteSize);
private:
bool IsCanRead();// 判断是否可以再进行读操作
bool IsCanWrite(int nByteSize);// 判读剩余的空间是否能够容纳nByteSize字节的数据
int RemainingSpace();// 计算剩余的空间大小
private:
char buffer[BUFFER_MAX_SIZE];
int nIdWrite; // 读下标标记
int nIdRead; // 写下标标记
};
判断可读可写
首先缓冲区中没有任何数据时,nIdWrite、nIdRead读写下标都为0。为了判断缓冲区中是否还有数据可读或者可写,我判断的依据是:
1)当nIdWrite 等于 nIdRead时,表示缓冲区内没有任何数据可读;否则存在可读的数据
2)当剩余的空间小于我们所需要的空间时,表示缓冲区不能再继续写数据,否则可以进行写数据
3)这里说明一下,当剩余空间 等于 我们所需要的空间时,实际上也可以进行写数据的,只不过需要用一个标记来标记缓冲区是否有数据。否则,这个时候nIdWrite **等于**nIdRead,无法区分缓冲区到底是有数据还是满了的情况!
#include "stdafx.h"
#include "RingBuffer.h"
#include <string.h>
RingBuffer::RingBuffer()
{
nIdRead = nIdWrite = 0;
}
RingBuffer::~RingBuffer()
{
}
// 计算剩余空间的大小
int RingBuffer::RemainingSpace()
{
if (nIdWrite >= nIdRead) // 减去读取Id到队列末尾剩余的,再加上队列开始到没读的
return BUFFER_MAX_SIZE - nIdWrite + nIdRead;
return nIdRead - nIdWrite; // 读取的Id减去 写入的Id
}
// 判断是否具有可读的数据,当nIdRead == nIdWrite时,具有数据可读
bool RingBuffer::IsCanRead()
{
if (nIdRead == nIdWrite)
return false;
return true;
}
// 判断是否可写
bool RingBuffer::IsCanWrite(int nByteSize)
{
if (RemainingSpace() > nByteSize)
return true;
return false;
}
// 将数据放入缓冲区
bool RingBuffer::WriteRingBuffer(char* pSrc, int nByteSize)
{
if (!IsCanWrite(nByteSize))
return false;
if (nIdWrite >= nIdRead)
{
if (BUFFER_MAX_SIZE - nIdWrite >= nByteSize)
{
memcpy(buffer + nIdWrite, pSrc, nByteSize);
nIdWrite = (nIdWrite + nByteSize) % BUFFER_MAX_SIZE;
}
else
{
int nTail = BUFFER_MAX_SIZE - nIdWrite;
int nHead = nByteSize - nTail;
memcpy(buffer + nIdWrite, pSrc, nTail);
memcpy(buffer, pSrc + nTail, nHead);
nIdWrite = nHead;
}
}
else
{
memcpy(buffer + nIdWrite, pSrc, nByteSize);
nIdWrite = nIdWrite + nByteSize;
}
return true;
}
// 从缓冲区读取数据
bool RingBuffer::ReadRingBuffer(char* pBuffer, int &nByteSize)
{
if (!IsCanRead())
return false;
if (nIdRead < nIdWrite)
{// 当write的下标 > read的下标时,直接读取一个完整的包
nByteSize = *((int*)(buffer + nIdRead));
memcpy(pBuffer, buffer + nIdRead, nByteSize);
nIdRead = nIdRead + nByteSize;
}
else
{
char szByteSize[4];
int nTemp = sizeof(int);
// 获取尾部还剩余的数据量
int nTail = BUFFER_MAX_SIZE - nIdRead;
// 拷贝出保存当前包数据的大小内存
if (nTemp <= nTail)
{
memcpy(szByteSize, buffer + nIdRead, nTemp);
}
else
{
memcpy(szByteSize, buffer + nIdRead, nTail);
memcpy(szByteSize + nTail, buffer, nTemp - nTail);
}
// 得到当前包的数据大小
nByteSize = *(int*)szByteSize;
// 拷贝数据包
if (nByteSize <= nTail)
{
memcpy(pBuffer, buffer + nIdRead, nByteSize);
nIdRead = (nIdRead + nByteSize) % BUFFER_MAX_SIZE;
}
else
{// 先拷贝缓冲区尾部剩余的数据,再从头部拷贝当前数据包剩余的数据
int nHead = nByteSize - nTail;
memcpy(pBuffer, buffer + nIdRead, nTail);
memcpy(pBuffer + nTail, buffer, nHead);
nIdRead = nHead;
}
}
return true;
}