zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Vue(小案例_vue+axios仿手机app)_go实现退回上一个路由
    nyoj 635 Oh, my goddess
    nyoj 587 blockhouses
    nyoj 483 Nightmare
    nyoj 592 spiral grid
    nyoj 927 The partial sum problem
    nyoj 523 亡命逃窜
    nyoj 929 密码宝盒
    nyoj 999 师傅又被妖怪抓走了
    nyoj 293 Sticks
  • 原文地址:https://www.cnblogs.com/findumars/p/6009469.html
Copyright © 2011-2022 走看看