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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM