Qt通过UDP传图片,实现自定义分包和组包
2017-06-14 22:18
447 查看
一.包头结构体
[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中绘制控件、图片、文字
相关文章推荐
- Qt通过UDP传图片,实现自定义分包和组包
- Qt通过UDP传图片,实现自定义分包和组包
- Android通过自定义ImageView控件实现图片的缩放和拖动的实现代码
- qt利用委托:QStyledItemDelegate,实现tableview 的表格项的自定义显示,如插入图片,绘制控件
- Asp.net MVC防止图片盗链的实现方法,通过自定义RouteHandler来操作
- Qt键盘驱动处理类的实现:Qt键盘驱动处理类的实现,通过Qt的插件机制实现嵌入式开发中的自定义键盘处理。
- qt通过点击按钮跳转当前图片坐标实现图片移动
- 自定义View通过PorterDuffXfermode实现图片遮罩效果
- Qt中如何利用 png 图片来实现自定义形状的窗口
- Qt实现透明无边框,无关闭按钮,带自定义图片的窗体实例代码
- ListView通过自定义的Adapter实现异步下载显示网络图片
- 通过自定义数据绑定类实现MVC中图片上传
- 通过自定义View实现圆形图片
- ListView通过自定义的Adapter实现异步下载显示网络图片
- Qt 之 自定义按钮 在鼠标 悬浮、按下、松开后的效果(全部通过QSS实现)
- 通过调用qt的assistant来实现自定义文档(qhc格式)
- Asp.net MVC防止图片盗链的实现方法,通过自定义RouteHandler来操作
- Qt 自定义model实现文件系统的文件名排序(重定义sort函数即可。忽然开窍了:其实捕捉点击Header事件,内部重排序,全部刷新显示即可)
- 通过盘古分词自定义规则功能实现软件版本号的提取
- C++ GUI Programming with Qt 4 - 10.4 实现自定义代理(delegate)