首页 > 代码库 > 用于拼包和解码的环形缓冲区类

用于拼包和解码的环形缓冲区类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
    /// <summary>
    /// 环形缓冲区
    /// </summary>
    public class CRawBuffer
    {
        byte[] m_BufArr;
        int m_i4BufLen;   //数据缓冲区大小
        public int m_i4ReadPos;   //读游标
        public int m_i4WritePos;  //写游标

        const int const_maxLen = 102400;

        public CRawBuffer(int i4MaxQueueBufferSize)
        {
            m_BufArr = new byte[i4MaxQueueBufferSize];
            if (i4MaxQueueBufferSize <= 0 || i4MaxQueueBufferSize > const_maxLen)
            {
                m_BufArr = new byte[const_maxLen];
                m_i4BufLen = const_maxLen;
            }
            else
            {
                m_BufArr = new byte[i4MaxQueueBufferSize];
                m_i4BufLen = i4MaxQueueBufferSize;
            }
            //m_BufArr.SetValue(0, 0, m_BufArr.Length - 1);
            m_i4ReadPos = 0;
            m_i4WritePos = 0;
        }

        public void SetRawDataToBuffer(byte[] byteArr, int nDataLen)
        {
            for (int i = 0; i < nDataLen; i++)
            {
                //接收的数据量达到缓冲区最大值,则将m_i4WritePos置0,从头开始计数(循环计数)
                if (m_i4WritePos == m_i4BufLen)
                {
                    m_i4WritePos = 0;
                }
                m_BufArr[m_i4WritePos] = byteArr[i];
                m_i4WritePos++;//更新要写入数据位置    

                //接收的数据量达到缓冲区最大值,则将m_i4WritePos置0,从头开始计数(循环计数)
                if (m_i4WritePos == m_i4BufLen)
                {
                    m_i4WritePos = 0;
                }
            }
        }

        public void SetUsedLength(int i4Length)
        {
            //根据已经使用数据个数,移动开始标记指针
            m_i4ReadPos = m_i4ReadPos + i4Length;
            if (m_i4ReadPos >= m_i4BufLen)
                m_i4ReadPos = m_i4ReadPos - m_i4BufLen;
        }

        public int GetData(byte[] byteArr, int i4Length)
        {
            int i4RealLength = 0;
            int i4ReadPosEnd = m_i4WritePos;//固定数据末尾位置
            if (i4ReadPosEnd > m_i4ReadPos)//正常情况,读数据的最新位置大于上次读完数据的位置,取出数据
            {
                i4RealLength = i4ReadPosEnd - m_i4ReadPos;//实际数据长度
                if (i4RealLength >= i4Length)//实际数据长,要求获取数据短,这样就只给需要的长度数据
                {

                    memcpy(byteArr, 0, m_BufArr, m_i4ReadPos, i4Length);
                    i4RealLength = i4Length;
                }
                else//要求获取数据比实际数据长
                {
                    memcpy(byteArr, 0, m_BufArr, m_i4ReadPos, i4RealLength);
                }
            }
            else if (i4ReadPosEnd < m_i4ReadPos)//越界情况,读数据的最新位置小于上次读完数据的位置,分两次拷贝数据                                         
            {
                //检查缓冲区末尾长度是否够用m_i4BufLen
                if (m_i4BufLen - m_i4ReadPos >= i4Length)//尾段够用
                {
                    memcpy(byteArr, 0, m_BufArr, m_i4ReadPos, i4Length);
                    i4RealLength = i4Length;
                }
                else//必须跨段两次写入
                {
                    //先读完缓冲区,再从缓冲区头部开始读数
                    memcpy(byteArr, 0, m_BufArr, m_i4ReadPos, m_i4BufLen - m_i4ReadPos);
                    i4RealLength = m_i4BufLen - m_i4ReadPos + i4ReadPosEnd;//实际数据长度
                    if (i4RealLength >= i4Length)//两段长度之和大于i4Length
                    {
                        memcpy(byteArr, m_i4BufLen - m_i4ReadPos, m_BufArr, 0, i4Length - (m_i4BufLen - m_i4ReadPos));
                        i4RealLength = i4Length;
                    }
                    else//两段长度之和小于i4Length
                    {
                        memcpy(byteArr, m_i4BufLen - m_i4ReadPos, m_BufArr, 0, i4ReadPosEnd);
                    }
                }
            }
            else return 0;//i4ReadPosEnd 和 m_i4ReadPos 重叠

            return i4RealLength;
        }

        private void memcpy(byte[] targetArr, int nTargetOffset, byte[] sourceArr, int nSourceOffset, int nDataLen)
        {
            for (int i = 0; i < nDataLen; i++)
            {
                targetArr[i + nTargetOffset] = sourceArr[i + nSourceOffset];
            }
        }
    }
}

用于拼包和解码的环形缓冲区类