UDP传输图片(分包)

前提:需要了解QUdp的简单通信,比如收发个字符串

      QPixmap图片类,以此类来加载图片

      QBuffer和QByteArray来记录数据

      memcpy函数的用法

 

分包概念:举个例子就是客户端(C)给服务器(S)发送数据时,不一次性发送,而是将一个数据分成几份发送,然后在接收方将收到的数据再拼接在一起;比如:要发送字符串“123456789”给Server,我们可以先后发送“1”,“2”,“3”,“4”,“5”,“6”,“7”,“8”,“9”;在Server接收到数据后再拼接成“132456789”;

为了确定我们收到的是什么数据,是不是我们需要的数据:就需要定义一个报文头,来标识数据,使Server可以确定收到的数据是我们需要的;这时发送的数据格式就是:报文头+数据;报文头部分定义一些报文需要的参数,此处为例,根据需求增删改;

传输图片为例:将图片转换成QByte类型,然后分段,之后每次发送的数据就是:包头+其中一段数据;收到后,根据包头的信息,将数据段拼接成一个整体数据,然后再转成图片

struct PackageHeader

{
    unsigned int uTransPackageHdrSize; //包头大小

    unsigned int uTransPackageSize; //当前包大小

    unsigned int uDataSize; //数据总大小

    unsigned int uDataPackageNum; //数据被分成包的个数

    unsigned int uDataPackageCurrIndex; //数据包当前的帧号

    unsigned int uDataPackageOffset; //数据包在整个数据中的偏移
};

const int UDP_MAX_SIZE=1200;  //定义一个包发送的数据大小

//发送端的代码,memcpy不可用,需要根据具体操作来实现

void Widget::on_pushButton_clicked()

{
    QPixmap image("D:/splash.png");//定义要发送的图片

    QBuffer buffer;//借助QBuffer保存图片数据

    buffer.open(QIODevice::ReadWrite);

    image.save(&buffer,"jpg");

    int dataLength=buffer.data().size();//图片Byte大小,即表示图片大小

    unsigned char*dataBuffer=(unsigned char*)buffer.data().data();//将QByteArray数据类型转换

    int packetNum=0;//该图片一共分了多少个包发送

    int lastPaketSize=0;//最后一个包的大小

    packetNum=dataLength/UDP_MAX_SIZE;//UDP_MAX_SIZE定义一个包的大小

    lastPaketSize=dataLength%UDP_MAX_SIZE;//最后一个包的大小

    int currentPacketIndex=0;//当前包的ID

    if(lastPaketSize!=0)//如果最后一个包不是空,

    {

        packetNum=packetNum+1;//总包数+1,即数据不满1200也算一个包

    }

    PackageHeader packageHead;//定义一个包头,方便接收的时候区分

    packageHead.uTransPackageHdrSize=sizeof(packageHead);//包头大小

    packageHead.uDataSize=dataLength;//数据总大小

    packageHead.uDataPackageNum=packetNum;//图片被分成几个包发送

   

    while(currentPacketIndexwriteDatagram((const char*)frameBuffer,packageHead.uTransPackageSize,QHostAddress("192.168.0.28"),port);  //udp发送数据

            if(length!=packageHead.uTransPackageSize)

            {//length的值是UDP发送是否成功的判断

                qDebug()<<"Failed to send image";

            }

            currentPacketIndex++;

        }

        else//这个部分发送的是最后一个包,有可能是不够一个包长度的(1200)

        {//        当前包大小 (最后一个包的大小)       包头大小          + 剩余数据的大小

            packageHead.uTransPackageSize=sizeof(PackageHeader)+(dataLength-currentPacketIndex*UDP_MAX_SIZE);

            //                数据包当前的帧号

            packageHead.uDataPackageCurrIndex=currentPacketIndex+1;

            //数据包在整个数据中的偏移

            packageHead.uDataPackageOffset=currentPacketIndex*UDP_MAX_SIZE;

            memcpy(frameBuffer,&packageHead,sizeof(PackageHeader));//将包头赋值给char*

            //将数据体的一个包的长度赋值给cahr*

            memcpy(frameBuffer+sizeof(PackageHeader),dataBuffer+packageHead.uDataPackageOffset,dataLength-currentPacketIndex*UDP_MAX_SIZE);

            //UDP发送

            int length= sender->writeDatagram((const char*)frameBuffer,packageHead.uTransPackageSize,QHostAddress("192.168.0.28"),port);  //udp发送数据

            if(length!=packageHead.uTransPackageSize)

            {//length的值是UDP发送是否成功的判断

                qDebug()<<"Failed to send image";

            }

            currentPacketIndex++;

        }

    }

}

//接收端代码,memcpy不可用,需要根据需求自己改

QByteArray imageData;

void Widget::showText()

{

    while(receiver->hasPendingDatagrams())

    {

        QByteArray data;  data.clear();//准备接收容器

        data.resize(receiver->pendingDatagramSize());//指定容器大小

        receiver->readDatagram(data.data(),data.size()) ;//将数据赋值给容器

        static int num=1;

        static uint size=0;

        PackageHeader*packageHead=(PackageHeader*)data.data();//将包头部分先取出来

        if(packageHead->uDataPackageCurrIndex==num)//判断是否是第几个包

        {

            num++;

            //数据部分大小    =       当前包的大小   -  包头大小

            size+=packageHead->uTransPackageSize-packageHead->uTransPackageHdrSize;//当前包的大小-包头的大小=数据的大小

            if(size>1024*1000)

            {//如果当前包数据超过1024*1000,说明数据过大,不是需要的数据

                qDebug()<<"image too big";

                num=1;

                size=0;

                return;

            }

            if(packageHead->uDataPackageOffset>1024*1000)

            {//如果当前包数据偏移量超过1024*1000,说明数据过大,不是需要的数据

                qDebug()<<"image too big";

                packageHead->uDataPackageOffset=0;

                num=1;

                size=0;

                return;

            }

            memcpy(imageData.data+packageHead->uDataPackageOffset,data.data()+packageHead->uTransPackageHdrSize,

                   packageHead->uTransPackageSize-packageHead->uTransPackageHdrSize);//将数据部分赋值到数据容器里

            //确定数据传输完毕后,将数据转换成QPixmap类型

            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->label->setPixmap(pixmap);

                num=1;

                size=0;

            }

        }

        else

        {

            num=1;

            size=0;

            memset(&imageData,0,sizeof(UdpUnpackData));

        }

    }

}

 

你可能感兴趣的:(网络通信)