#include "DataRecver.h"
#include "DataCreator.h"
#include "ProtocolData.h"
//数据接收者,模拟TCP接收端
CDataRecver::CDataRecver(QObject *parent)
:QObject(parent)
{
//内存缓冲区清空
m_buff.hasHead=false;
m_buff.totalLen=0;
m_buff.recevData.clear();
m_pDataCreator = new CDataCreator(); //数据发生器
CProtocal::instance()->createData(); //在内存中生成一个数据报向量,存在m_dataVector
m_pDataCreator->creataRawData(CProtocal::instance()->gerRawData()); //利用内存中的数据报向量,来生成原始数据
connect(m_pDataCreator,SIGNAL(signalNewData(QByteArray)),
this,SLOT(slotDataArrived(QByteArray))); //数据发生器发送一次数据报,接收者(本对象)就调用数据接收槽函数
connect(m_pDataCreator,SIGNAL(signalSendOver()),
this,SLOT(slotWorkOver())); //数据发生器中的数据报发送完毕,接收者(本对象)调用接收完成槽函数
}
CDataRecver::~CDataRecver()
{
}
void CDataRecver::startWork()
{
//内存缓冲区清空
m_buff.hasHead=false;
m_buff.totalLen=0;
m_buff.recevData.clear();
m_recvDataVector.clear(); //数据报向量清空
m_pDataCreator->startWork(); //数据发生器开始工作
}
//收数据
void CDataRecver::slotDataArrived(QByteArray array)
{
m_buff.recevData.append(array); //添加到内存接收缓冲区
//判断是否有文件头
checkBufferHasHead(m_buff);
//每个数据报接收完毕就进行解析,否则,等待下一次信号来临继续接收
quint32 size=m_buff.recevData.size();
if(size>=m_buff.totalLen)
{
parseBufferData(m_buff,m_recvDataVector); //解析数据报,并用一个向量保存接收到的数据报
}
qDebug()<<"current recv:"<<array.size()<<"total size:"<<m_buff.recevData.size();
}
//所有数据报接收完毕
void CDataRecver::slotWorkOver()
{
if(m_recvDataVector.size()==CProtocal::instance()->gerRawData().size());
//成功接收到多少个数据报
CProtocal::instance()->compareData(m_recvDataVector);
}
void CDataRecver::checkBufferHasHead(BufferData &bufferData)
{
//判断缓冲区是否包含报文头
//缓冲区原来有报文头,只需要继续读取数据
if(bufferData.hasHead)
{
return;
}
//之前没有报文头,加上这次读取的数据,再进行判断
int index=bufferData.recevData.indexOf(PRIVATE_HEAD);
if(index == -1)
{
//说明这次没有文件头
bufferData.recevData.clear();
return;
}
//这次有文件头
if(index>0)
{
bufferData.recevData.remove(0,index);
}
//可以确定缓冲区含有报文头,进行CRC校验
//取出协议中的各个分量
QDataStream out(&bufferData.recevData,QIODevice::ReadOnly);
quint32 header,cmd,len,crc;
QByteArray data;
out>>header>>cmd>>len>>crc>>data;
//如果没有通过CRC校验,说明数据仍然不是我们要的,清楚缓冲区所有内容
if(checkCRC(header,cmd,len,crc)==false)
{
cout<<"wrong crc";
bufferData.recevData.clear();
bufferData.totalLen=0;
bufferData.hasHead=false;
return;
}
//包含文件头并且通过CRC校验
bufferData.hasHead=true;
bufferData.totalLen=len;
}
//CRC校验
bool CDataRecver::checkCRC(quint32 header, quint32 cmd, quint32 len, quint32 crc)
{
bool isOK=false;
quint32 rightCRC=0;
rightCRC=header+cmd+len-PROTOCOL_LENGTH;
if(rightCRC==crc)
{
isOK=true;
}
return isOK;
}
//解析缓冲区的数据
void CDataRecver::parseBufferData(BufferData &bufferData, QVector<CProtocalData> &vector)
{
//检查缓冲区是否含有报文头
int index=bufferData.recevData.indexOf(PRIVATE_HEAD);
if(bufferData.recevData.size()==0)
{
return;
}
if(index==-1)
{
cout<<"can't find header when parsing";
return;
}
//如果有多个数据报在缓冲区中
while(index != -1)
{
if(index>0)
{
bufferData.recevData.remove(0,index);
}
//缓冲区当前数据长度小于协议长度,就退出循环等待下一次读取
if(bufferData.recevData.size()<PROTOCOL_LENGTH)
{
break;
}
//进行CRC校验
QDataStream out(&bufferData.recevData,QIODevice::ReadOnly);
quint32 header,cmd,len,crc;
QByteArray data;
out>>header>>cmd>>len>>crc>>data;
if(checkCRC(header,cmd,len,crc)==false)
{
qDebug()<<"wrong crc";
bufferData.recevData.clear();
bufferData.hasHead=false;
bufferData.totalLen=0;
break;
}
//若当前读取到的数据长度小于文件数据实际长度,就退出循环等待下一次读取
quint32 dataSize=data.size()+PROTOCOL_LENGTH;
if(len>dataSize)
{
break;
}
//当前数据报接收完毕,转化成ProtocalData,添加到用来保存 接收到的数据报的向量中,并从缓冲区冲移除
vector.append(CProtocal::toProtocalData((bufferData.recevData.mid(0,dataSize))));
bufferData.recevData.remove(0,dataSize);
//为下一个数据报的读取做准备工作
bufferData.hasHead=false;
index=bufferData.recevData.indexOf(PRIVATE_HEAD);
//如果报文头被截断,退出循环等待下一次读取
if(bufferData.recevData.size()-index<4)
{
break;
}
}
}