Qt::网络协议解析技巧

主要介绍一下解析网络协议常用的技巧

  1. 字符串直接转化为16进制字节
    例如将"0102FFAB"的字符串直接转化为:0102FFAB的16进制字符。
void QtWidgetsApplicationexample::string_to_Hex(QString& textContent, QByteArray& hex)
{
	QString _Space = " ";  //如果存在空格则去除空格
	int _size = textContent.length();
	while (_size - 2 > 0)
	{
		_size = _size - 2;
		textContent.insert(_size, " ");
	}
	textContent = textContent.trimmed();
	QStringList _textContentList = textContent.split(" ");
	for each (QString m_textContent in _textContentList)
	{
		if (!m_textContent.isEmpty())
		{
			hex.append((char)m_textContent.toInt(0, 16) & 0XFF);
		}
	}
}
    QByteArray _hex;
    QString _textContent = "0102FFAB";
    string_to_Hex(_textContent, _hex);
    qDebug() << _hex;
打印出:0102FFAB。
  1. 16进制字节直接转化为可展示的字符串

例如将0102FFAB的16进制字符直接转化为:“0102FFAB”的字符串。

void QtWidgetsApplicationexample::Hex_to_string(QByteArray& hex, QString& textContent)
{
	for (char byte : hex)
	{
		textContent.append(QString::number(static_cast<unsigned char>(byte), 16).rightJustified(2, '0').toUpper());
	}
	int _size = textContent.size();
	while (_size > 0)
	{
		_size = _size - 2;
		textContent.insert(_size, " ");
	}
}

	QByteArray _hex = QByteArray::fromHex("0102FFAB");
	QString _textContent;
	Hex_to_string(_hex, _textContent);
	qDebug()  << _textContent;

打印出:" 01 02 FF AB"

  1. 解析网络协议

假设,存在一个长度为19字节的长度的一直在刷新的网络消息需要读取解析,协议的帧头帧尾为固定值。前两位帧头为:AAAB,最后两位帧尾为BABB。(倒数第三位是0-15字节的CRC8校验值,关于CRC校验,可以阅读以前的文章)。

  • 首先判断收到的数据长度,是否大于等于19
  • 如果长度符合则判断帧头帧尾和校验位,全部正确则说明此数据为有效数据。
  • 最后解析字节的每一位,得到想要的数据。
    以上是主要思路,然后进行实现
	//1:使用递归按位寻找帧头
	//2:然后截取获取帧尾 和 检验码
	//3:校验,对比检验码
	//4:获取需要的值

	if (!findFrame_Header(data))
		return;

	if (!findFrame_ender(data))
		return;

	if (!findFrame_crc8(data))
		return;
	
	if (!findFrame_DataArea(data))
		return;

findFrame_Hexder(QByteArray& data)的实现:

const quint16 Frame_Header = 0XAAAB;//帧头为固定数据

bool ReciveMessageFromDoor::findFrame_Header(QByteArray& data)
{
	if (data.size() >= 19)                 //判断长度是否符合
	{		
		QDataStream inStream(data);//从data中读取数据
          inStream.setByteOrder(QDataStream::BigEndian);
		if (comparsion_Frame_Header(inStream))
		{
			qDebug() << u8"Find Frame header";
			return true;
		}
		else
		{
			data.remove(0, 1);
			if (findFrame_Header(data))
			{
				return true;
			}
		}
	}
	qDebug() << u8"Not Find Frame header";
	return false;
}

bool ReciveMessageFromDoor::comparsion_Frame_Header(QDataStream& data)
{
	quint16 _frame_header = 0X0000;
	data >> _frame_header;//将前两位数据读取到_frame_header中
	if (_frame_header == Frame_Header)
	{
		return true;
	}
	return false;
}

程序使用递归的方式判断当前数据是否满足使用。

findFrame_ender(QByteArray& data)的实现:

bool ReciveMessageFromDoor::findFrame_ender(QByteArray& data)
{
	//获取到帧头后,向后取第:17,18位是帧尾
	
	QByteArray _data  =  data.mid(17, 2);//从下标为17位开始,取两位数据
	QDataStream inStream(_data);
	inStream.setByteOrder(QDataStream::BigEndian);
	if (comparsion_Frame_Ender(inStream))
	{
		qDebug() << u8"Find Frame Ender";
		return true;
	}
	qDebug() << u8"Not Find Frame Ender";
	return false;
}
bool ReciveMessageFromDoor::comparsion_Frame_Ender(QDataStream& data)
{
	quint16 _frame_ender = 0X0000;
	data >> _frame_ender;
	if (_frame_ender == Frame_End)
	{
		return true;
	}
	return false;
}

findFrame_crc8(QByteArray& data)的实现:

bool ReciveMessageFromDoor::findFrame_crc8(QByteArray& data)
{
	//获取到帧头后,向后取第:16位是校验码
	//对0-15位进行CRC8校验,校验结果等于校验码
	QByteArray _dataCRC8 = data.mid(16, 1);
	quint8 _inCRC8 = _dataCRC8.at(0);
	QByteArray _dataArea = data.mid(0, 16);
	quint8 _CRC8 = crc8(_dataArea);
	if (_CRC8 == _inCRC8)
	{
		qDebug() << u8"CRC Frame right";
		return true;
	}
	qDebug() << u8"CRC Frame wrong";
	return false;
}

findFrame_DataArea(QByteArray& data)的实现,假设取第7个字节的第一位数据和第二位数据,判断是0还是1:

bool ReciveMessageFromDoor::findFrame_DataArea(QByteArray& data)
{
	//7
	QByteArray _byteSeven = data.mid(7, 1);
	getBitSeven(_byteSeven);
}

void ReciveMessageFromDoor::getBitSeven(QByteArray& data)
{

	int _Zero_Speed = getBytebitIndex(data, 0);
	qDebug() << _Zero_Speed;

	
	int _Enabled = getBytebitIndex(data, 1);
	qDebug() << _Enabled;
 
}

4.组装网络字节协议

请添加图片描述

如上图所示,下列代码演示如何组装19位长度的网络消息:

  • 前四位0,1,2,3为固定消息,第5位发递增的生命信号,6,7位为固定消息,8,9,10,11,12是时间,14,15,16是预留字节,17是CRC校验,18,19为固定消息。
const quint8 Frame_Header_One = 0XAA;
const quint8 Frame_Header_Two = 0XAB;
const quint8 Frame_End_One = 0XBA;
const quint8 Frame_End_Two = 0XBB;
const quint8 Door_Timing = 0X02;
QByteArray packageData;
bool TimeMessageToDoor::packagePollingMessage(QByteArray& packageData)
{
	packageData.append(Frame_Header_One);
	packageData.append(Frame_Header_Two);
	packageDoorAddressComplement(packageData);
	packageLifeSignal(packageData);
	packageData.append(1, char(0));
	packageData.append(Door_Timing);
	packageCurrentTime(packageData);
	packageData.append(3, char(0));//补充三个为0的字节
	quint8 _crc = crc8(packageData);
	packageData.append(_crc);//省略
	packageData.append(Frame_End_One);
	packageData.append(Frame_End_Two);
	return true;
}


bool TimeMessageToDoor::packageDoorAddressComplement(QByteArray& inStream)
{
	if (b_useCycle && m_cyclemethod < 4)
	{
		m_cyclemethod = m_cyclemethod + 1;
	}
	else
	{
		m_cyclemethod = m_cyclemethod;
	}


	switch (m_cyclemethod)
	{
	case 1:
		inStream.append(Door_One_Address);
		inStream.append(Door_One_Address_Complement);
		break;
	case 2:
		inStream.append(Door_Two_Address);
		inStream.append(Door_Two_Address_Complement);
		break;
	case 3:
		inStream.append(Door_Three_Address);
		inStream.append(Door_Three_Address_Complement);
		break;
	case 4:
		inStream.append(Door_Four_Address);
		inStream.append(Door_Four_Address_Complement);
		break;
	default:
		break;
	}
	return true;
}

bool TimeMessageToDoor::packageLifeSignal(QByteArray& inStream)
{
	m_curMode = m_curMode + 1;
	if (m_curMode > 255)
	{
		m_curMode = 1;
	}
	quint8 mode = (quint8)m_curMode;
	inStream.append(mode);
	return true;	
}

bool TimeMessageToDoor::packageCurrentTime(QByteArray& inStream)
{
	QDateTime _dataTime = QDateTime::currentDateTime();
	QString _strYMD = _dataTime.toString("yyyy-MM-dd");
	QString _strHMS = _dataTime.toString("hh:mm:ss");
	//时间采用BCD格式
	QString _strYear = _strYMD.split("-")[0];
	int _intYear = decimal_bcd_code(_strYear.toInt() - 2000);

	QString _strMonth = _strYMD.split("-")[1];
	int _intMonth = decimal_bcd_code(_strMonth.toInt());

	QString _strDay = _strYMD.split("-")[2];
	int _intDay = decimal_bcd_code(_strDay.toInt());


	QString _strHour = _strHMS.split(":")[0];
	int _intHour = decimal_bcd_code(_strHour.toInt());

	QString _strMinute = _strHMS.split(":")[1];
	int _intMinute = decimal_bcd_code(_strMinute.toInt());

	QString _strSecond = _strHMS.split(":")[1];
	int _intSecond = decimal_bcd_code(_strSecond.toInt());

	inStream.append(quint8(_intYear));
	inStream.append(quint8(_intMonth));
	inStream.append(quint8(_intDay));
	inStream.append(quint8(_intHour));
	inStream.append(quint8(_intMinute));
	inStream.append(quint8(_intSecond));
	return true;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值