一.包头结构体

  1. //包头
  2. struct PackageHeader
  3. {
  4. //包头大小(sizeof(PackageHeader))
  5. unsigned int uTransPackageHdrSize;
  6. //当前包头的大小(sizeof(PackageHeader)+当前数据包长度)
  7. unsigned int uTransPackageSize;
  8. //数据的总大小
  9. unsigned int uDataSize;
  10. //数据被分成包的个数
  11. unsigned int uDataPackageNum;
  12. //数据包当前的帧号
  13. unsigned int uDataPackageCurrIndex;
  14. //数据包在整个数据中的偏移
  15. unsigned int uDataPackageOffset;
  16. };

每包数据由包头和包体组成,包头用于标记每包数据的特征,包体是图片根据指定大小分出的每段数据,这里指定大小为const int UDP_MAX_SIZE=1200。

为何要分包可参考:TCP、UDP数据包大小的限制

二.分包与组包

1.分包

  1. int dataLength=buffer.data().size();
  2. unsigned char *dataBuffer=(unsigned char *)buffer.data().data();
  3. int packetNum = 0;
  4. int lastPaketSize = 0;
  5. packetNum = dataLength / UDP_MAX_SIZE;
  6. lastPaketSize = dataLength % UDP_MAX_SIZE;
  7. int currentPacketIndex = 0;
  8. if (lastPaketSize != 0)
  9. {
  10. packetNum = packetNum + 1;
  11. }
  12. PackageHeader packageHead;
  13. packageHead.uTransPackageHdrSize=sizeof(packageHead);
  14. packageHead.uDataSize = dataLength;
  15. packageHead.uDataPackageNum = packetNum;
  16. unsigned char frameBuffer[1024*1000];
  17. memset(frameBuffer,0,1024*1000);
  18. while (currentPacketIndex < packetNum)
  19. {
  20. if (currentPacketIndex < (packetNum-1))
  21. {
  22. packageHead.uTransPackageSize = sizeof(PackageHeader)+UDP_MAX_SIZE;
  23. packageHead.uDataPackageCurrIndex = currentPacketIndex+1;
  24. packageHead.uDataPackageOffset = currentPacketIndex*UDP_MAX_SIZE;
  25. memcpy(frameBuffer, &packageHead, sizeof(PackageHeader));
  26. memcpy(frameBuffer+sizeof(PackageHeader), dataBuffer+packageHead.uDataPackageOffset, UDP_MAX_SIZE);
  27. int length=udpsocketSend->writeDatagram(
  28. (const char*)frameBuffer, packageHead.uTransPackageSize,
  29. QHostAddress(ui->lineEditIP->text()), ui->lineEditPort->text().toInt());
  30. if(length!=packageHead.uTransPackageSize)
  31. {
  32. qDebug()<<"Failed to send image";
  33. }
  34. currentPacketIndex++;
  35. }
  36. else
  37. {
  38. packageHead.uTransPackageSize = sizeof(PackageHeader)+(dataLength-currentPacketIndex*UDP_MAX_SIZE);
  39. packageHead.uDataPackageCurrIndex = currentPacketIndex+1;
  40. packageHead.uDataPackageOffset = currentPacketIndex*UDP_MAX_SIZE;
  41. memcpy(frameBuffer, &packageHead, sizeof(PackageHeader));
  42. memcpy(frameBuffer+sizeof(PackageHeader), dataBuffer+packageHead.uDataPackageOffset, dataLength-currentPacketIndex*UDP_MAX_SIZE);
  43. int length=udpsocketSend->writeDatagram(
  44. (const char*)frameBuffer, packageHead.uTransPackageSize,
  45. QHostAddress(ui->lineEditIP->text()), ui->lineEditPort->text().toInt());
  46. if(length!=packageHead.uTransPackageSize)
  47. {
  48. qDebug()<<"Failed to send image";
  49. }
  50. currentPacketIndex++;
  51. }
  52. }

先将图片转换为QBuffer,这样就可以获取图片的数据和长度,然后根据指定大小UDP_MAX_SIZE分包。在包头中设置每包数据的特征,然后将包体加到包头后面发送出去。

2.组包

  1. static int num = 1;
  2. static uint size = 0;
  3. PackageHeader *packageHead = (PackageHeader *)datagram.data();
  4. if (packageHead->uDataPackageCurrIndex == num)
  5. {
  6. num++;
  7. size += packageHead->uTransPackageSize-packageHead->uTransPackageHdrSize;
  8. if (size > 1024*1000)
  9. {
  10. qDebug()<<"image too big";
  11. num = 1;
  12. size = 0;
  13. return;
  14. }
  15. if (packageHead->uDataPackageOffset > 1024*1000)
  16. {
  17. qDebug()<<"image too big";
  18. packageHead->uDataPackageOffset = 0;
  19. num = 1;
  20. size = 0;
  21. return;
  22. }
  23. memcpy(imageData.data+packageHead->uDataPackageOffset, datagram.data()+packageHead->uTransPackageHdrSize,
  24. packageHead->uTransPackageSize-packageHead->uTransPackageHdrSize);
  25. if ((packageHead->uDataPackageNum == packageHead->uDataPackageCurrIndex)
  26. && (size == packageHead->uDataSize))
  27. {
  28. imageData.length = packageHead->uDataSize;
  29. QImage image;
  30. image.loadFromData((uchar *)imageData.data,imageData.length,"JPG");
  31. QPixmap pixmap=QPixmap::fromImage(image);
  32. ui->labelImage_2->setPixmap(pixmap);
  33. recvImageNum++;
  34. ui->lineEditRevFrame->setText(QString::number(recvImageNum));
  35. ui->lineEditRevSize->setText(QString::number(imageData.length));
  36. memset(&imageData,0,sizeof(UdpUnpackData));
  37. num = 1;
  38. size = 0;
  39. }
  40. }
  41. else
  42. {
  43. num = 1;
  44. size = 0;
  45. memset(&imageData,0,sizeof(UdpUnpackData));
  46. }

组包是分包的逆过程,根据包头中“数据的总大小”和“数据被分成包的个数”两个字段可以判断组包是否完整,如果完整就在接收端显示出来。
三.示例

界面包括发送端和接收端,接收端的IP地址是自动获取的本机IP地址,上图将发送端的IP地址设置为与接收端IP地址相同,可实现自发自收。

每秒帧数可实时设置每秒发送图片的张数,发送帧数表示一共发送了多少张,接收帧数表示一共接收了多少张,图片大小表示每张图片多少Byte。

可将示例运行于两台计算机,实现双向收发。

源码链接:见http://blog.csdn.net/caoshangpa/article/details/52681572的评论

http://blog.csdn.net/caoshangpa/article/details/52681572

Qt通过UDP传图片,实现自定义分包和组包的更多相关文章

  1. 异步SOCKET分包和组包的一种通用算法

    unit uPackage;// 应用协议// cxg 2016-9-23// 包=包头+包体 interface uses SysUtils, Classes, PeachCtrl.Net.Iocp ...

  2. Socket之UDP分包组包

    一般传输大的文件和信息的时候需要涉及到分包和组包,方法有很多,下面一种是借鉴了别人的思路,供大家参考哈 分包 1.取出需要传输的文件和字符的长度和大小放入缓存区里面: 2.设定固定传输的长度,用需要传 ...

  3. 使用 Qt 获取 UDP 数据并显示成图片

    一个项目,要接收 UDP 数据包,解析并获取其中的数据,主要根据解析出来的行号和序号将数据拼接起来,然后将拼接起来的数据(最重要的数据是 R.G.B 三个通道的像素值)显示在窗口中.考虑到每秒钟要接收 ...

  4. 使用 Qt 获取 UDP 数据并显示成图片(2)

    本文首发于 BriFuture 的 个人博客 在我的前一篇文章 使用 Qt 获取 UDP 数据并显示成图片 中,我讲了如何用 Python 模拟发送数据,如何在 Qt 中高效的接收 UDP 数据包并将 ...

  5. 7.Vue-Quill-Editor图片插入自定义

    Vue-Quill-Editor图片插入自定义 前言: 因为在项目中前端采用了Vue来实现,正好用到了富文本编辑器这一块,于是,经过技术上的选择,决定使用Vue-Quill-Editor. 使用的过程 ...

  6. Qt自适应大小显示图片,添加菜单

    由于后面的图像处理需要UI,OpenCV自带也不怎么会,MFC实在懒得学的.听同学说Qt不错,就用Qt做UI了. 本文主要介绍三个内容:在Qt Creator中使用OpenCV2.Qt中自适应显示图片 ...

  7. iOS开发——UI进阶篇(十八)核心动画小例子,转盘(裁剪图片、自定义按钮、旋转)图片折叠、音量震动条、倒影、粒子效果

    一.转盘(裁剪图片.自定义按钮.旋转) 1.裁剪图片 将一张大图片裁剪为多张 // CGImageCreateWithImageInRect:用来裁剪图片 // image:需要裁剪的图片 // re ...

  8. 用qt代码怎样编写图片保存格式[qt4.6]

    用qt代码怎样编写图片保存格式 qt提供了多个保存图片的接口,比较常用的接口如下 bool QPixmap::save ( const QString & fileName, const ch ...

  9. iOS-AFNetworking-上传图片

    一.AFNetworking上传图片 /** 需要Demo,可留言 */ 1.利用AFnetworking上传图片. 2.注意将UIImage类型转化为NSData类型,传给后台. 二.Demo // ...

随机推荐

  1. [网络配置相关]——netstat命令

    netstat:显示网络状态信息 -a   显示所有连接状态的网络的所有选项-l    仅显示LISTEN状态的连接-n   直接显示IP地址,而不通过域名服务器-p   把进程名和进程PID也显示出 ...

  2. AppDelegate中的方法解析

    // 当应用程序启动完毕的时候就会调用(系统自动调用) -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOp ...

  3. “我爱淘”冲刺阶段Scrum站立会议5

    完成任务: 由于我们的思路做了些改变,重新设计了界面的布局. 计划任务: 实现数据库的链接,将页面布局完善. 遇到问题: 使用webservice对数据的提取

  4. php大文件下载

    <?php header("Content-Type:text/html;charset:utf-8"); //class FileDownServer{ //$file_n ...

  5. maven插件:tomcat插件和jetty插件的区别

    在程序是多模块结构的时候,使用tomcat的maven插件和jetty的maven插件有细微差别: 1.tomcat7-maven-plugin   可以直接在parent的邮件直接运行:tomcat ...

  6. bzoj 2038 莫队算法

    莫队算法,具体的可以看10年莫涛的论文. 大题思路就是假设对于区间l,r我们有了一个答案,那么对于区间l,r+1,我们 可以暴力的转移一个答案,那么对于区间l1,r1和区间l2,r2,需要暴力处理 的 ...

  7. C#异常处理策略

    1.如果某些异常,本组件无法处理,不要捕获,但要声明有这个异常.例如SecurityException. 2.如果某些异常,本组件可以处理,捕获并处理它,不再声明此异常.例如DirectoryNotF ...

  8. cf 61E. Enemy is weak 树状数组求逆序数(WA) 分类: Brush Mode 2014-10-19 15:16 104人阅读 评论(0) 收藏

    #include <iostream> #include <algorithm> #include <cstdio> #include <cstring> ...

  9. A*(A星)算法python实现

    在春节放假前两天我偶然看到了A\*算法(A\*算法是一个启发式的地图寻路算法),感觉挺有意思.正好放假前也没有什么事情,就花了一个下午写出算法的骨架,节后又花了半天时间完善屏幕输出的细节并且调试完成. ...

  10. 宠物AI(个人觉得有问题)

    //宠物AI流程 .刚开始添加宠物 Monster被动State:EnumMonster被NULL MonsterStat:EnumPet跟随 .附近有怪物就改成攻击模式(相关的收尾工作) void ...