QT实现TCP通信解析结构体数据播放视频
最近有个项目需要用TCP接收传来的结构体数据如下所示:
#define BLOCKSIZE IMG_WIDTH * IMG_HEIGHT * 3
struct recvBuf
{
float scale_value;
int width;
int height;
int channels;
char buf[BLOCKSIZE];
};
其中,buf是视频帧,scale_value是判断是否该截取该帧保存下来,其余就是宽高和通道.
技术概要
最主要的问题就是粘包问题.所以本文就围绕如何解决这个问题来展开.由于TCP传来的数据是以流的形式,而每次只能读取一定长度的数据.对于图片数据,一般需要多批次才能读取一张完整的数据.这就会出现一个问题怎么判断这张图片已经完全读取到了?方法有很多,本文采用的方法是根据一个结构体的长度是固定的,所以可以用先进现出的队列思想,即当接受到一个完整的结构体长度时就出列这个结构体.
代码流程
//信号与槽实际就是观察者模式(发布-订阅模式)。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。connect将信号与槽链接
connect(m_server,&QTcpServer::newConnection,[=](){
//有客户端链接就开启线程读取数据
m_receiver = m_server->nextPendingConnection();
qDebug()<<"readyread...";
static int number = 0;
m_thread =QThread::create([=]{
qDebug()<<"thread...";
connect(m_receiver,&QTcpSocket::readyRead,[=](){
//data为QByteArray,初始化为空,readAll()方法读取通道中的全部数据,但是需要知道这个方法的读取量是有限度的一般为几kb
data.append(m_receiver->readAll());
QImage img;
//如果读取到的数据长度小于dataLen(为一个结构体的长度)则返回继续读取
if(data.size() < dataLen) {
return;
}else{
qDebug()<<"size:"<<data.size();
//这里由于解析的速度慢于发送的速度,所以要循环读取
while(data.size() - dataLen>=0){
//当大于一个结构体长度时进行读取,加载图片
float fl = 0;
memcpy(&fl,data.mid(0,sizeof(float)).data(),sizeof(float));
QByteArray img_src(sub1.data(),BLOCKSIZE);
img.loadFromData(img_src);
QPixmap pix = QPixmap::fromImage(img);
//宽高为固定值
pix.scaled(1280,720,Qt::KeepAspectRatio);
m_ql->setPixmap(pix);
if(fl != 0){
ui->l_result->setPixmap(pix);
}
//出队一个完整的结构体
data.remove(0,dataLen);
}
}
});
});
m_thread->start();
});
小结
对于TCP数据流传送来的结构体进行解析,用到了队列的思想等到接受一个完整的结构体数据时就将它播放,立即出队.