0 背景
一般使用TCP传输数据都会涉及到粘包和拆包的问题,而Qt写的程序多作为客户端,因此主要解决的问题是拆包的问题。面对一次发来了大量的数据包,但是信号却只触发一次,也就是只做了一次拆分了,那就会导致有一部分后面的数据包没有得到处理,那怎么处理这种情况呢?
1 处理
使用递归处理,设置递归条件来再次处理,设置递归边界作为跳出处理。
例如:
//套接字
QTcpSocket* tcpSocket;
qint64 totalBytes = 0;//发送数据的总大小
qint64 receivedBytes = 0;//已收到的
QByteArray infoBlock;//帧体内容
QByteArray inBlock;//临时存储的数据
QByteArray s_frameHead;//帧头
QByteArray s_frameContent;//帧体
QByteArray s_frameTail;//帧位
///客户端
//建立套接字连接
tcpSocket = new QTcpSocket(this);
//处理接受连接 &QTcpSocket::connected
connect(tcpSocket, &QAbstractSocket::connected, this, &ShowImage::receiveConnect);
关联信号和槽函数
//接受数据
connect(tcpSocket, &QAbstractSocket::readyRead, this, &ShowImage::dealReceiveData);
//断开连接
connect(tcpSocket, &QAbstractSocket::disconnected, this, &ShowImage::tcpDisconnected);
//显示错误
connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(displayError(QAbstractSocket::SocketError)));
编写处理数据的槽函数:
void dealReceiveData(){
//递归边界:跳出处理
if(tcpSocket->bytesAvailable() == 0) return;
//处理帧头
if(receivedBytes < sizeof (qint64) && infoBlock.length() == 0){
if(tcpSocket->bytesAvailable() >= sizeof (qint64) && s_frameHead.size() == 0){
s_frameHead = tcpSocket->read(sizeof (qint64));
//qDebug()<<"s_frameHead:"<<s_frameHead.toHex().toUpper();
}else{
// qDebug()<<"接收头返回";
return;
}
}
//持续接收帧体数据
if(receivedBytes < totalBytes && tcpSocket->bytesAvailable() > 0){
//QByteArray inBlock = tcpSocket->readAll();
if(tcpSocket->bytesAvailable() >= (totalBytes - receivedBytes)){
inBlock = tcpSocket->read(totalBytes - receivedBytes);
}else{
inBlock = tcpSocket->readAll();
}
infoBlock.append(inBlock);
receivedBytes += inBlock.size();
//qDebug()<<"inBlock:"<<byteArrayToHexStr(inBlock);
//qDebug()<<"持续接收receivedBytes:"<<receivedBytes;
inBlock.resize(0);
}
//一帧数据收满开始处理
if(receivedBytes == totalBytes){
//处理
}
//如果还是有残留数据,再递归处理数据
//此处还可以增加特判帧头里的类型字段,来判断是否要递归立即处理,还是等下次数据来触发信号后再处理
if(tcpSocket->bytesAvailable() > 0 )){
dealReceiveData();
}
}