之前给大家分享了一个使用python发图片数据、Qt server接收图片的Demo。之前的Demo用于传输小字节的图片是可以的,但如果是传输大的图片,使用socket无法一次完成发送该怎么办呢?本次和大家分享一个对大的图片拆包、组包、处理粘包的例子。

程序平台:ubuntu 、Qt 5.5.1

为了对接收到的图像字节进行组包,我们需要对每包数据规定协议,协议如下图:

每包数据前10个字节对应含义如下:前两个字节对应数据包类型,中间四字节预留,最后四字节是包内数据实际长度。对应协议图片更方便刚开始上手的兄弟理解。

对协议有了一个了解后,接下来说下程序结构。客户端按照协议发送图片字节,服务器接收字节,如果客户端发多少服务器就收多少那可真是太好了,然而意外总是如期而至。服务器这边由于socket的缓冲总是会粘包,所以服务器这边主要工作是拆包和组包,这也是整个程序组中最重要的部分。其次就是服务器在接收图片时为了响应更及时,单独使用一个线程进行接收图片,这里面我使用的是Qt的moveToThread。也使用过linux的socket以及线程接收图片,感觉性能要比Qt封装过的要好,大家有需要的话可以在公众号后台留言。

接下来跟着程序走:

客户端发送部分:

①读取图片字节

1 voidWidget::on_pbn_readPicture_clicked()2 {3 m_picturePath = m_picturePath +"/auboi5.jpg";4 QPixmap pix;5 bool ret =pix.load(m_picturePath);6

7 QBuffer buffer;8 buffer.open(QIODevice::ReadWrite);9 bool ret2 = pix.save(&buffer,"jpg");10

11 m_pictureByteArray =buffer.data();12

13 if(ret2)14 {15 QString str = "read image finish!";16 ui->textEdit->append(str);17 }18 }

读取图片字节主要用到了Qt的QPixmap 类,这个不细说,大家具体可参考Qt文档。图片字节被读取到m_pictureByteArray中,成功后在textEdit显示read image finish!。

②发送图像拆包

1 QByteArray dataPackage;2

3 //command 0 ,package total size

4 QDataStream dataHead(&dataPackage,QIODevice::ReadWrite);5 dataHead << quint16(0);6 dataHead << quint32(0);7 dataHead <write(dataPackage);10 dataPackage.clear();11

12 QThread::msleep(20);

这里我拿医一包数据举例说明。第一包数据是将读取到的整张图片的大小发送出去,以判断接收方接收到的数据是否完整。主要涉及到Qt一些数据类型的转换,如将整型字节存入QByteArray 中使用QDataStream 。之后将数据包大小重新设置为40960,方便服务器处理粘包。

③发送utf8编码的中文

1 voidWidget::on_pbn_sendChinese_clicked()2 {3 QByteArray dataPackage;4 QByteArray chinese = "阶级终极形态假设!";5

6 //command 3

7 QDataStream dataTail(&dataPackage,QIODevice::ReadWrite);8 dataTail << quint16(3);9 dataTail << quint32(0);10 dataTail <

12 dataPackage = dataPackage.insert(10,chinese.data(),chinese.size());13 dataPackage.resize(40960);14

15 mp_clsTcpSocket->write(dataPackage);16 }

这部分直接略过了,大家参考下即可。

2.服务器接收部分(重要):

①线程中槽函数接收图片数据拆包

1 voidTcpServerRecvImage::slot_readClientData()2 {3 QByteArray buffer;4 buffer = mp_clsTcpClientConnnect->readAll();5

6 m_bufferSize =buffer.size();7 m_total = m_total +buffer.size();8 qDebug() << "socket Receive Data size:" << m_bufferSize <

10 if(m_bufferSize == 40960)11 {12 emit signal_sendImagedataPackage(buffer);13 qDebug() << "直接发送";14 return;15 }16

17

18 if((m_picture.size() + m_bufferSize) == 40960)19 {20 m_picture.append(buffer);21

22 emit signal_sendImagedataPackage(m_picture);23 m_picture.clear();24 qDebug() << "拼接后40960";25 return;26 }27

28

29 if((m_picture.size() + m_bufferSize) < 40960)30 {31 m_picture.append(buffer) ;32 qDebug() << "直接拼接";33 return;34 }35

36 if((m_picture.size() + m_bufferSize) > 40960)37 {38 //case one

39 if((m_bufferSize > 40960) && (m_picture.size() == 0))40 {41 while(m_bufferSize/40960)42 {43 QByteArray data = buffer.left(40960);44 buffer.remove(0,40960);45

46 emit signal_sendImagedataPackage(data);47 m_bufferSize =buffer.size();48

49 if((m_bufferSize/40960 == 0) && (m_bufferSize!=0))50 {51 m_picture.append(buffer);52 }53 QThread::msleep(2);54 }55 return;56 }57

58 //case two

59 if((m_bufferSize > 40960) && (m_picture.size() > 0))60 {61 int frontLength = 40960 -m_picture.size();62 QByteArray data =buffer.left(frontLength);63 buffer.remove(0,frontLength);64

65 m_picture.append(data);66 if(40960 ==m_picture.size())67 {68 emit signal_sendImagedataPackage(m_picture);69 m_picture.clear();70 }71

72 m_bufferSize =buffer.size();73

74 while(m_bufferSize/40960)75 {76 QByteArray data = buffer.left(40960);77 buffer.remove(0,40960);78

79 emit signal_sendImagedataPackage(data);80 m_bufferSize =buffer.size();81

82 if((m_bufferSize/40960 == 0) && (m_bufferSize!=0))83 {84 m_picture.append(buffer);85 }86 QThread::msleep(2);87 }88 return;89 }90 }91 }

程序有那么一点长,我先说下他们在做的事情:

1> 如果接收到的字节是40960字节,直接发到主线程处理数据的槽中

2> 如果接收到的字节加上缓存中的字节数目小于40960,直接将数据追加到 m_picture中 【请原谅我40960没有用宏定义】

3> 如果接收到的字节加上缓存中的字节数目等于40960,直接发送

4> 如果接收到的字节加上缓存中的字节数目大于40960,分两种

①接收到的字节是40960的整数倍

if((m_bufferSize/40960 == 0) && (m_bufferSize!=0))

{

m_picture.append(buffer);

}

如果不加上面这个追加函数,则会有数据解析失败

②接收到的字节不是40960的整数倍

int frontLength = 40960 - m_picture.size();

QByteArray data = buffer.left(frontLength);

buffer.remove(0,frontLength);

先取出那一包数据剩余的部分,然后拼成一包发出。

之前试过直接追加到m_picture中,但经常有数据解析失败,

然后看例子,试了这个,结果......

②主线程处理40960数据包

1 voidWidget::slot_imagePackage(QByteArray imageArray)2 {3 m_imageCount++;4 QString number =QString::number(m_imageCount);5 ui->textEdit->append(number);6

7 QByteArray cmdId = imageArray.left(2);8 QDataStream commandId(cmdId);9 quint16 size;10 commandId >>size;11

12 if(0 ==size)13 {14 QByteArray cmdId = imageArray.mid(6,9);15 QDataStream commandId(cmdId);16 quint32 size;17 commandId >>size;18 qDebug() << "图片的总字节数" <

21 if(2 ==size)22 {23 QByteArray cmdId = imageArray.mid(6,9);24 QDataStream commandId(cmdId);25 quint32 size;26 commandId >>size;27 qDebug() << "图片包尾字节数" <

30 if(3 ==size)31 {32 QByteArray cmdId = imageArray.mid(6,9);33 QDataStream commandId(cmdId);34 commandId >>m_dataSize;35 qDebug() << "汉子字节数" <

38 switch(size)39 {40 case 1:41 imageArray.remove(0,10);42 m_imagePackage.append(imageArray);43 break;44

45 case 2:46 imageArray.remove(0,10);47 m_imagePackage.append(imageArray);48

49 m_pix.loadFromData(m_imagePackage,"jpg");50 ui->lb_image->setPixmap(m_pix.scaled(595.2,792)); //500 * 375

51 break;52

53 case 3:54 imageArray.remove(0,10);55 imageArray.resize(m_dataSize);56 ui->textEdit->append(QTextCodec::codecForMib(106)->toUnicode(imageArray));57 break;58

59 default:60 break;61 }62

63 }

这部分简单介绍下。识别对应命令ID,对对应的数据包处理。这里面我没有对图像总的接收到的数据判断,大家具体情况具体处理。

(QTextCodec::codecForMib(106)->toUnicode(imageArray) 这个是对QByteArray转换为utf8编码的处理,最后得到的是中文。

最后看下结果图:

服务器接收---->>>

客户端发送--->>>

服务器我在windows下试过,接收数据处理不对,有机会我会再研究下的。

刚开始写这种图片组包的程序没什么经验,写出来是为了让更多刚接触编程的同志不再那么孤立无援!共勉!

需要整个工程的公众号后台留言~

qt 串口粘包_Qt Socket 传输图片——图像拆包、组包、粘包处理相关推荐

  1. qt 串口 环形缓存_qt linux串口 缓冲区多大

    满意答案 Zc的爱丶很美 2016.09.11 采纳率:51%    等级:9 已帮助:515人 一.程序设计的基础,例如:基本的编程语言基础,至少对数据类型.程序的结构及流程控制等最基本的内容要相当 ...

  2. 文件传输_python socket实现文件传输(防粘包)

    1.文件传输的要点: 采用iterator(迭代器对象)迭代读取,提高读取以及存取效率: 通过for line in file_handles逐行conn.send(): 2.socket粘包问题: ...

  3. Python3之socket编程(TCP/UDP,粘包问题,数据传输、文件上传)

    一.socket的定义 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后 ...

  4. qt串口阻塞_Qt串口操作

    嵌入式设备经常要用到串口与下位机进行通信.本篇主要介绍Qt串口相关操作,环境(Qt5.2+msvc2010编译) 本文主要内容如下: A.枚举主机的串口名称 ​foreach(constQSerial ...

  5. Socket封包、拆包、粘包

    接触Socket通信的过程中,遇到了各种有关数据包的问题.这里做一下记录. 一.Socket粘包 1.什么是粘包? 答:顾名思义,其实就是多个独立的数据包连到一块儿. 2.什么情况下需要考虑粘包? 答 ...

  6. 什么是粘包?socket 中造成粘包的原因是什么? 粘包的处理方式

    1.粘包的概念 粘包:多个数据包被连续存储于连续的缓存中,在对数据包进行读取时由于无法确定发生方的发送边界,而采用某一估测值大小来进行数据读出,若双方的size不一致时就会使指发送方发送的若干包数据到 ...

  7. QT开发(五十)——QT串口编程基础

    QT开发(五十)--QT串口编程基础 一.QtSerialPort简介 1.串口通信基础 目前使用最广泛的串口为DB9接口,适用于较近距离的通信.一般小于10米.DB9接口有9个针脚. 串口通信的主要 ...

  8. create显示中文乱码 qt_Ubuntu下Qt串口助手接收中文乱码问题

    问题描述: 在ubuntu中用Qt开发的串口助手,在接收单片机(STM32 F103)发来的中文时,出现乱码情况. 接收中文乱码 问题已解决,感谢Qt交流qq群中的各位大佬. 解决思路: 可以检查一下 ...

  9. android qt 串口通信,Qt串口通信开发之QSerialPort模块详细使用方法与实例

    Qt串口通信开发之QSerialPort模块详细使用方法与实例 发布时间:2020-10-23 12:19:05 来源:脚本之家 阅读:111 作者:沧海一笑-dj Qt串口通信基础及名词说明 串口通 ...

最新文章

  1. xshell使用指南
  2. 7-2 整除分块 (15 分)
  3. 华为云GaussDB深耕数字化下半场,持续打造数据库根技术
  4. Character,String相关方法,Int,double互相转换
  5. matlab hpopup2,matlabpopupmenu的问题
  6. asyncawait异步请求处理办法
  7. 使用Easy Duplicate Photo Finder for Mac如何查找重复的图片?
  8. 用python做一个抖音上很火的罗盘时钟
  9. 短信验证码接口开发代码
  10. SIT1043 带唤醒及故障保护的低功耗CAN FD总线收发器 对标TJA1043
  11. 【跟我一起学Linux之Ubuntu】-概述与安装配置笔记
  12. 文件夹别名路径 请求图片时报错
  13. 52数学能力测评历年真题及答案(五年级)
  14. 5.1.2 消费者的加入组和同步组
  15. Python基础之闭包函数
  16. 分享一个外国免费在线领各类软件激活码的网站
  17. js中history对象
  18. 1003. 我要通过!
  19. 元旦的庆贺,是每家每户的快乐
  20. 科普系列--天气气象的监测和设备

热门文章

  1. Docker:镜像操作和容器操作
  2. 周五晚上看了变形金刚
  3. java中什么时候不能用泛型_java中泛型的正确使用姿势
  4. 日期如何比较 java_如何比较Java中的日期?
  5. java中继承和多态的实验,Java中的继承和多态
  6. begin end会产生事务吗_无线信号放大器会产生同频干扰吗?
  7. java都市男人心痒痒_说的男人心痒痒的情话 让男人心痒痒的话,谁能帮我弄几句呀?...
  8. linux 故障注入_libfiu
  9. 公式没有编号_知乎公式编辑器的一些小技巧 amp; 使用规范
  10. matlab中任意两边之和大于第三边,无法赋值,左侧大小1*1,右侧1*3,代码报错,但是看不出来两边大小不相等啊...