【C++ 数据根据帧头分包以及位偏移后数据滑帧处理】


前言

在网络通讯等数据流处理的时候,往往遇到粘包,或者数据位偏移,本文介绍下如何处理。


提示:以下是本篇文章正文内容,下面案例可供参考

一、数据分析要点

        1.缓冲区找到帧头,确定数据长度;然后截取;保留剩余数据

        2.重复 1步骤

        3.如果需要位怕偏移,需要偏移后进行字节拼装整理;

二、代码实现

.h代码如下(示例):

class CFrameTransChg
{
public :
    CFrameTransChg(); //默认构造 1ACFFC1D
    CFrameTransChg(unsigned char* Header, int len); //任意帧头处理
    void AddBuf(const unsigned char*, unsigned int len);//添加数据
    unsigned char* GetBuf(unsigned int& len);  //获取解析数据 可以用 While 判断返回值 进行大量数据处理
    const static int FramLen = 1024; //截取长度
    unsigned int Len() {return m_lenIn;    }//当前数据长度
protected:
    //按位找头
    unsigned char*  ResultBitIdx(unsigned char * buf, int len, int & rtLen, int & rtBitidx, int& bFind, int offset);
    void ProcData();
private:
    unsigned char* m_Trans;
    unsigned int m_lenOut;
    unsigned char* m_InPut;
    unsigned int m_lenIn;
    unsigned char* m_header;
    unsigned int m_lenHeader;

cpp代码如下(示例):

CFrameTransChg::CFrameTransChg()
{
	m_header = new unsigned char[4];
	int Head = 0x1DFCCF1A;
	memcpy(m_header,&Head, 4);
	m_lenHeader = 4;
	m_Trans = nullptr;
}
CFrameTransChg::CFrameTransChg(unsigned char * Header, int len)
{
	m_header = new unsigned char[len];
	m_Trans = nullptr;
	memcpy(m_header, Header, len);
}
void CFrameTransChg::AddBuf(const unsigned char * buf, unsigned int len)
{
	BYTE* oldDt = m_InPut;	
	m_InPut = new  BYTE[m_lenIn + len];
	if(oldDt)
	{ 
		memcpy(m_InPut, oldDt, m_lenIn);
		delete[]oldDt;
	}
	memcpy(m_InPut+ m_lenIn, buf, len);
	m_lenIn += len;

}
unsigned char * CFrameTransChg::GetBuf(unsigned int & len) 
{
	ProcData();
	if(m_Trans)
	{
		BYTE* rt = new BYTE[FramLen];
		memcpy(rt, m_Trans, FramLen);
		delete[]m_Trans;
		m_Trans = nullptr;
		return rt;
	}
	return m_Trans;
}
unsigned char * CFrameTransChg::ResultBitIdx(unsigned char * buf, int len, int & rtLen, int & rtBitidx, int& bFind, int offset)
{
	BYTE* search= m_header;
	int searchCount = 0;
	int bitLen = len * sizeof(BYTE) * 8;
	int lst = 0; //下一次索引
	BYTE* resultBuf = new BYTE[len];
	rtLen = 0;
	memset(resultBuf, 0, len * sizeof(BYTE));
	int offsetIdx = offset % 8;
	bFind = 0;
	for (int i = offsetIdx; i < bitLen; ) //循环一次
	{
		int idxByte = i / 8;
		int idxBit = i % 8;
		int Left = 8 - idxBit;
		BYTE Hb = buf[idxByte] << idxBit;
		BYTE Lb = 0;
	
		if (idxBit > 0)
		{
			if (idxByte < len - 1)//modify 20231009
				Lb = (buf[idxByte + 1] >> Left);
			else
				break;
		}
		BYTE BitIdxNew = Hb | Lb;
		if (bFind)//找到了 赋值
		{
			resultBuf[rtLen++] = BitIdxNew;		
			i += 8; 
			if (rtLen == FramLen - m_lenHeader) //足够了 不找了 需要重置最后一个位
			{ 
				if(idxByte< (bitLen-1))
					buf[idxByte + 1] = (buf[idxByte + 1] << idxBit);
				break;
			}
			continue;
		}else
		{ 
			if (BitIdxNew == *search)
			{
				searchCount++;
				search++;
				lst = i;
				if (searchCount == m_lenHeader)//第一次找到
				{
					rtBitidx = i- m_lenHeader*8; //位地址
					bFind = 1;
				}
				i += 8;
				continue;
			}
			if(searchCount>0)//没用找全Header 重置i索引为往前回滚8个Byte
			{
				i = lst; //
			}
			searchCount = 0;
			search = m_header;
		}
		i++; 
	}
	return resultBuf;
}
void CFrameTransChg::ProcData()
{
	int rtBitidx = 0;
	int rtLen = 0;
	int Inpt = m_lenIn > CFrameTransChg::FramLen+4 ? CFrameTransChg::FramLen+4 : m_lenIn; // 2048 理论上选择   CFrameTransChg::FramLen
	if (Inpt <= 100)
		return;
	int bFind;
	BYTE* resultBuf = ResultBitIdx(m_InPut, Inpt, rtLen, rtBitidx, bFind, 0);
	BYTE* oldDt = m_InPut;

	if (rtLen == 0) //保留头长度下次校验
	{
		if(m_lenIn - Inpt >0)
		{ 
			m_InPut = new BYTE[m_lenIn - Inpt];
			memcpy(m_InPut, oldDt + Inpt, m_lenIn - Inpt);
			delete[]oldDt;
			m_lenIn -= Inpt;
		}
	}
	else
	{ 
		if (rtLen == FramLen - m_lenHeader)//剩余保留
		{
			m_InPut = new BYTE[m_lenIn - rtBitidx / 8 - FramLen];
			memcpy(m_InPut, oldDt + rtBitidx / 8 + FramLen, m_lenIn - rtBitidx / 8 - FramLen);
			delete[]oldDt;
			if (m_Trans) delete[]m_Trans;
			m_Trans = nullptr;
			m_Trans = new BYTE[FramLen];
			m_lenOut = FramLen;
			memcpy(m_Trans, m_header, m_lenHeader);
			memcpy(m_Trans+ m_lenHeader, resultBuf, rtLen);
			m_lenIn -= (rtBitidx / 8 +FramLen);
		}
		else //保留头之前的
		{
			if(m_lenIn>0)
			{ 
				m_InPut = new BYTE[m_lenIn - rtBitidx / 8];
				memcpy(m_InPut, oldDt + rtBitidx / 8, m_lenIn - rtBitidx / 8);
				delete[]oldDt;
				m_lenIn -= (rtBitidx / 8);
			}
	}
	}
	delete[]resultBuf;
}

三、测试

帧头1ACFFC1D 定长1K 位偏>>2测试


总结

在数据传输的项目中找帧头,非常普遍,方法仅供初学者参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值