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

来源:互联网 发布:标准差 知乎 编辑:程序博客网 时间:2024/05/17 20:01

一.包头结构体

//包头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的评论


4 0
原创粉丝点击