一.包頭結構體
- //包頭
- struct PackageHeader
- {
- //包頭大小(sizeof(PackageHeader))
- unsigned int uTransPackageHdrSize;
- //當前包頭的大小(sizeof(PackageHeader)+當前數據包長度)
- unsigned int uTransPackageSize;
- //數據的總大小
- unsigned int uDataSize;
- //數據被分成包的個數
- unsigned int uDataPackageNum;
- //數據包當前的幀號
- unsigned int uDataPackageCurrIndex;
- //數據包在整個數據中的偏移
- unsigned int uDataPackageOffset;
- };
每包數據由包頭和包體組成,包頭用於標記每包數據的特征,包體是圖片根據指定大小分出的每段數據,這里指定大小為const int UDP_MAX_SIZE=1200。
為何要分包可參考:TCP、UDP數據包大小的限制
二.分包與組包
1.分包
- int dataLength=buffer.data().size();
- unsigned char *dataBuffer=(unsigned char *)buffer.data().data();
- int packetNum = 0;
- int lastPaketSize = 0;
- packetNum = dataLength / UDP_MAX_SIZE;
- lastPaketSize = dataLength % UDP_MAX_SIZE;
- int currentPacketIndex = 0;
- if (lastPaketSize != 0)
- {
- packetNum = packetNum + 1;
- }
- PackageHeader packageHead;
- packageHead.uTransPackageHdrSize=sizeof(packageHead);
- packageHead.uDataSize = dataLength;
- packageHead.uDataPackageNum = packetNum;
- unsigned char frameBuffer[1024*1000];
- memset(frameBuffer,0,1024*1000);
- while (currentPacketIndex < packetNum)
- {
- if (currentPacketIndex < (packetNum-1))
- {
- packageHead.uTransPackageSize = sizeof(PackageHeader)+UDP_MAX_SIZE;
- packageHead.uDataPackageCurrIndex = currentPacketIndex+1;
- packageHead.uDataPackageOffset = currentPacketIndex*UDP_MAX_SIZE;
- memcpy(frameBuffer, &packageHead, sizeof(PackageHeader));
- memcpy(frameBuffer+sizeof(PackageHeader), dataBuffer+packageHead.uDataPackageOffset, UDP_MAX_SIZE);
- int length=udpsocketSend->writeDatagram(
- (const char*)frameBuffer, packageHead.uTransPackageSize,
- QHostAddress(ui->lineEditIP->text()), ui->lineEditPort->text().toInt());
- if(length!=packageHead.uTransPackageSize)
- {
- qDebug()<<"Failed to send image";
- }
- currentPacketIndex++;
- }
- else
- {
- packageHead.uTransPackageSize = sizeof(PackageHeader)+(dataLength-currentPacketIndex*UDP_MAX_SIZE);
- packageHead.uDataPackageCurrIndex = currentPacketIndex+1;
- packageHead.uDataPackageOffset = currentPacketIndex*UDP_MAX_SIZE;
- memcpy(frameBuffer, &packageHead, sizeof(PackageHeader));
- memcpy(frameBuffer+sizeof(PackageHeader), dataBuffer+packageHead.uDataPackageOffset, dataLength-currentPacketIndex*UDP_MAX_SIZE);
- int length=udpsocketSend->writeDatagram(
- (const char*)frameBuffer, packageHead.uTransPackageSize,
- QHostAddress(ui->lineEditIP->text()), ui->lineEditPort->text().toInt());
- if(length!=packageHead.uTransPackageSize)
- {
- qDebug()<<"Failed to send image";
- }
- currentPacketIndex++;
- }
- }
先將圖片轉換為QBuffer,這樣就可以獲取圖片的數據和長度,然后根據指定大小UDP_MAX_SIZE分包。在包頭中設置每包數據的特征,然后將包體加到包頭后面發送出去。
2.組包
- static int num = 1;
- static uint size = 0;
- PackageHeader *packageHead = (PackageHeader *)datagram.data();
- if (packageHead->uDataPackageCurrIndex == num)
- {
- num++;
- size += packageHead->uTransPackageSize-packageHead->uTransPackageHdrSize;
- if (size > 1024*1000)
- {
- qDebug()<<"image too big";
- num = 1;
- size = 0;
- return;
- }
- if (packageHead->uDataPackageOffset > 1024*1000)
- {
- qDebug()<<"image too big";
- packageHead->uDataPackageOffset = 0;
- num = 1;
- size = 0;
- return;
- }
- memcpy(imageData.data+packageHead->uDataPackageOffset, datagram.data()+packageHead->uTransPackageHdrSize,
- packageHead->uTransPackageSize-packageHead->uTransPackageHdrSize);
- if ((packageHead->uDataPackageNum == packageHead->uDataPackageCurrIndex)
- && (size == packageHead->uDataSize))
- {
- imageData.length = packageHead->uDataSize;
- QImage image;
- image.loadFromData((uchar *)imageData.data,imageData.length,"JPG");
- QPixmap pixmap=QPixmap::fromImage(image);
- ui->labelImage_2->setPixmap(pixmap);
- recvImageNum++;
- ui->lineEditRevFrame->setText(QString::number(recvImageNum));
- ui->lineEditRevSize->setText(QString::number(imageData.length));
- memset(&imageData,0,sizeof(UdpUnpackData));
- num = 1;
- size = 0;
- }
- }
- else
- {
- num = 1;
- size = 0;
- memset(&imageData,0,sizeof(UdpUnpackData));
- }
組包是分包的逆過程,根據包頭中“數據的總大小”和“數據被分成包的個數”兩個字段可以判斷組包是否完整,如果完整就在接收端顯示出來。
三.示例

界面包括發送端和接收端,接收端的IP地址是自動獲取的本機IP地址,上圖將發送端的IP地址設置為與接收端IP地址相同,可實現自發自收。
每秒幀數可實時設置每秒發送圖片的張數,發送幀數表示一共發送了多少張,接收幀數表示一共接收了多少張,圖片大小表示每張圖片多少Byte。
可將示例運行於兩台計算機,實現雙向收發。
源碼鏈接:見http://blog.csdn.net/caoshangpa/article/details/52681572的評論

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