环形缓冲区

我们再处理网络数据包时,可能会将接受到的网络数据包放入缓冲区去做进一步的处理,这里我自己根据自己的需要用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;
}

猜你喜欢

转载自blog.csdn.net/llmys/article/details/78805046
今日推荐