您的位置:首页 > 编程语言 > Qt开发

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

2017-06-14 22:18 447 查看


转载 http://blog.csdn.net/caoshangpa/article/details/52681572
一.包头结构体

[cpp]
view plain
copy

print?

//包头
4000
  
struct PackageHeader  
{  
    //包头大小(sizeof(PackageHeader))  
    unsigned int uTransPackageHdrSize;  
    //当前包头的大小(sizeof(PackageHeader)+当前数据包长度)  
    unsigned int uTransPackageSize;  
    //数据的总大小  
    unsigned int uDataSize;  
    //数据被分成包的个数  
    unsigned int uDataPackageNum;  
    //数据包当前的帧号  
    unsigned int uDataPackageCurrIndex;  
    //数据包在整个数据中的偏移  
    unsigned int uDataPackageOffset;  
};  

//包头
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.分包

[cpp]
view plain
copy

print?

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++;  
    }  
}  

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.组包

[cpp]
view plain
copy

print?

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));  
}  

static int num = 1;
static uint size = 0;

PackageHeader *packageHead = (PackageH
bfb3
eader *)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
 
 
上一篇Qt调用jrtplib实现单播、多播和广播

下一篇Qt之窗口动画(下坠、抖动、透明度)

  相关文章推荐


Qt总结

[分享]比较全的电脑网络基础知识

Windows系统及应用技巧二十六篇

网管教程+从入门到精通软件篇

Windows系统及应用技巧二十六篇

Qt中如何利用 png 图片来实现自定义形状的窗口

qt利用委托:QStyledItemDelegate,实现tableview 的表格项的自定义显示,如插入图片,绘制控件

Qt自定义委托在QTableView中绘制控件、图片、文字
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐