• Qt通过UDP传图片,实现自定义分包和组包


    一.包头结构体

    [cpp] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    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.分包

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

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

    2.组包

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

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

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

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

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

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

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

  • 相关阅读:
    对于python中的self,cls,decorator的理解
    获得平台无关的文件锁
    Python 字符编码判断
    Flex 减肥
    Reporting Service报表开发
    JavaScript 中的单例模式 (singleton in Javascript)
    asp.net MVC 权限设计
    c# IO&&线程 打造 定时打开指定程序
    JavaScript 实现接口 (Interfaces In JavaScript)
    C#温故而知新—闲话.Net
  • 原文地址:https://www.cnblogs.com/findumars/p/6009469.html
Copyright © 2020-2023  润新知