前提:需要了解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(currentPacketIndex<packetNum)//当前包的ID小于总的包数,说明没传完数据,即可以继续传
{
unsigned char frameBuffer[1024*1000];
memset(frameBuffer,0,1024*1000);//清零
if(currentPacketIndex<(packetNum-1))//数据量够UDP_MAX_SIZE的长度,也就是此时不是发的最后一个包
{
packageHead.uTransPackageSize=sizeof(PackageHeader)+UDP_MAX_SIZE;//当前包大小=包头大小+数据大小
packageHead.uDataPackageCurrIndex=currentPacketIndex+1;//当前包ID默认是0,+1使开始ID为1
packageHead.uDataPackageOffset=currentPacketIndex*UDP_MAX_SIZE;//偏移量
memcpy(frameBuffer,&packageHead,sizeof(PackageHeader));//将包头赋值进容器
memcpy(frameBuffer+sizeof(PackageHeader),dataBuffer+packageHead.uDataPackageOffset,UDP_MAX_SIZE);//将数据部分赋值给容器
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++;
}
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));
}
}
}