Qt通过UDP传图片,实现自定义分包和组包
2016-09-27 16:35
633 查看
一.包头结构体
为何要分包可参考:TCP、UDP数据包大小的限制
二.分包与组包
1.分包
2.组包
三.示例
界面包括发送端和接收端,接收端的IP地址是自动获取的本机IP地址,上图将发送端的IP地址设置为与接收端IP地址相同,可实现自发自收。
每秒帧数可实时设置每秒发送图片的张数,发送帧数表示一共发送了多少张,接收帧数表示一共接收了多少张,图片大小表示每张图片多少Byte。
可将示例运行于两台计算机,实现双向收发。
源码链接:见http://blog.csdn.net/caoshangpa/article/details/52681572的评论
//包头 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的评论
相关文章推荐
- Qt通过UDP传图片,实现自定义分包和组包
- Qt通过UDP传图片,实现自定义分包和组包
- Asp.net MVC防止图片盗链的实现方法,通过自定义RouteHandler来操作
- 自定义View通过PorterDuffXfermode实现图片遮罩效果
- ListView通过自定义的Adapter实现异步下载显示网络图片
- Qt实现透明无边框,无关闭按钮,带自定义图片的窗体实例代码
- 通过调用qt的assistant来实现自定义文档(qhc格式)
- qt通过点击按钮跳转当前图片坐标实现图片移动
- 通过自定义数据绑定类实现MVC中图片上传
- qt利用委托:QStyledItemDelegate,实现tableview 的表格项的自定义显示,如插入图片,绘制控件
- Qt 之 自定义按钮 在鼠标 悬浮、按下、松开后的效果(全部通过QSS实现)
- Android通过自定义ImageView控件实现图片的缩放和拖动的实现代码
- Qt中如何利用 png 图片来实现自定义形状的窗口
- ListView通过自定义的Adapter实现异步下载显示网络图片
- Qt键盘驱动处理类的实现:Qt键盘驱动处理类的实现,通过Qt的插件机制实现嵌入式开发中的自定义键盘处理。
- Asp.net MVC防止图片盗链的实现方法,通过自定义RouteHandler来操作
- 通过自定义View实现圆形图片
- C++ GUI Programming with Qt 4 - 10.4 实现自定义代理(delegate)
- (源码实例)通过层DIV实现,当鼠标放在链接上面,显示图片及文字
- c# UDP通过广播实现群发功能