Qt中实现UDP的分包和组包——参考“草上爬”的博客

简介: Qt中实现UDP的分包和组包

一、为啥我们要分包组包?直接发不行吗?

最初你可能会存在这样的疑惑?所以我们需要了解下TCP和UDP在Qt中的区别。这里参考了阿拉丁的博客 顺便引用他的图;至于TCP和UDP相应的C/S架构图也可以通过这个兄弟的博客了解,当然还有TCP和UDP在Qt中如何实现。

①UDP和TCP表格对比

在这里插入图片描述

②在Qt中使用UDP和TCP的一些函数

在这里插入图片描述

在这里插入图片描述

③阅读关于Qt中UDP的writeDatagram

通过阅读下图的文档便可以知道:UDP一次性发送的数据量是有限的,所以我们必须要分包!!! 至于为啥UDP需要分包,TCP不需要,我这里大胆猜想:TCP其实也是需要拆分的,只不过它内部已经实现了我们组包的机制了,其实就是更牛逼的UDP,而今天我们的主题就是要用UDP实现:阉割版本的TCP
在这里插入图片描述

二、直接开整

①一些需要参考的知识类:Qt的一些文件设备类

参考某知乎博主南理汉子的回答,说实话我这里也有一些没有整清楚,文件IO这块,只能说我中午不能学(早晚都学);没懂这块也可以直接跳过这块,然后知道QByteArray就行了。

②包头?

包头有啥作用?很明显包头就是用来补充数据包的信息的,举个例子:包头就是诸葛亮留给刘备去江东的三个妙计,刘备带上三个锦囊,去江东遇到困难就打开锦囊获取里头的妙计(这例子有点牵强说实在)。对于一堆数据来说:包头就是诸葛亮的锦囊妙计 当数据到达对端的时候,直接解析包头,获取信息,通过这些信息,把数据依次排序、组装最终重新组合成新的数据,妙哉!!(ps:众所周知:接收端收到的数据包都是乱序的)下面我们来看看包头结构:
在这里插入图片描述

③如何分包?

很显然,把数据包切成一块一块的就行了如下图:
在这里插入图片描述
在这里插入图片描述
在代码中如何体现:通过memcpy将我们想要的数据,按照指定的大小,拷贝到申请的缓存区即可:需要源码可以去草上爬的博客评论区瞅瞅) 完成把数据切块后,又得把数据包头给加上,很明显还是通过memcpy我们申请缓存区后,先把包头加在前面,在加入数据,如图:
在这里插入图片描述
下面是分包的一个大概流程图:
在这里插入图片描述

代码如何体现:

申请数据缓冲区
memcpy(数据缓冲区开始地址,包头数据,包头大小)memcpy(数据缓冲区开始地址+数据偏移地址,切割的数据,数据大小);

代码如下:切忌不可偷懒直接粘贴代码,下面是一部分代码可供学习参考,如果需要完整源码去“草上爬”的博客评论区获取:

 PackageHeader packageHead;//定义一个包头

    packageHead.uTransPackageHdrSize=sizeof(packageHead);//包头大小
    packageHead.uDataSize = dataLength;//数据的总大小
    packageHead.uDataPackageNum = packetNum;//数据被分成包的个数
    packageHead.wOpcode= nOpcode;

    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;//当前下标+1
            packageHead.uDataPackageOffset = (currentPacketIndex)*UDP_MAX_SIZE;//偏移量=下标*数据包最大量

            memcpy(frameBuffer, &packageHead, sizeof(PackageHeader));//拷贝包头到缓存区
            memcpy(frameBuffer+sizeof(PackageHeader), dataBuffer+packageHead.uDataPackageOffset, UDP_MAX_SIZE);//包头后面+数据

            int length=my_udp->writeDatagram(
                        (const char*)frameBuffer, packageHead.uTransPackageSize,
                        my_ip_port.ip, my_ip_port.port);

            if(length!=packageHead.uTransPackageSize)
            {
   
   
                qDebug()<<"Failed to send image";
            }
            else
            {
   
   
                // ui->msg_record->append("发送成功包:"+currentPacketIndex);
                qDebug()<<"Success to send image";
            }
            currentPacketIndex++;
        }

④如何组包?

话不多说,直接上图,同样需要一块缓存区,然后通过memcpy把接收到的数据给分为:包头+数据 然后放进申请的缓存区进行取出包头,取出数据,拼接等一系列操作就行了。
在这里插入图片描述
下面是组包流程图:
在这里插入图片描述

来点代码意思意思:直接CV是跑步不起来的

    PackageHeader *packageHead = (PackageHeader *)datagram.data();
    if (packageHead->uDataPackageCurrIndex == num)//如果下标为1则
    {
   
   
        num++;//下标++
        size += packageHead->uTransPackageSize-packageHead->uTransPackageHdrSize;//大小为:当前包大小-包头大小
    if (size > 1024*1000)
    {
   
   
        ui->msg_record->append("image too big");
        num = 1;
        size = 0;
        return;
    }
    if (packageHead->uDataPackageOffset > 1024*1000)
    {
   
   
        ui->msg_record->append("image too big");
        packageHead->uDataPackageOffset = 0;
        num = 1;
        size = 0;
        return;
     }
    memcpy(imageData.data+packageHead->uDataPackageOffset, datagram.data()+packageHead->uTransPackageHdrSize,
     packageHead->uTransPackageSize-packageHead->uTransPackageHdrSize);

三、总结

关于解决这个问题: 研究别人的论文确实是以一种解决问题的好途径,CSDN上确实是 “在垃圾堆里找宝贝”
关于网络协议这块一点不足: 需要从底层认真研究网络协议,好好把王道书再瞅瞅。
关于后续安排: 马上踏入工作岗位,得加强对C++的学习,希望一切顺利。

相关文章
|
3月前
|
网络协议
Qt中的网络编程(Tcp和Udp)运用详解以及简单示范案例
Tcp和Udp是我们学习网络编程中经常接触到的两个通讯协议,在Qt也被Qt封装成了自己的库供我们调用,对于需要进行网络交互的项目中无疑是很重要的,希望这篇文章可以帮助到大家。 是关于Qt中TCP和UDP的基本使用和特点:
499 7
|
3月前
|
Linux 开发者 iOS开发
QT:基于QMediaPlayer制作的视频播放器(最下方有整合包,可直接运行)
QMediaPlayer是Qt多媒体模块中的一个核心类,它提供了播放音频和视频内容的功能。这个类的设计旨在简化跨平台的媒体播放,使得开发者能够在多种操作系统(如Linux、Windows、macOS及移动平台)上轻松集成多媒体播放能力到他们的应用中,而无需关心底层实现细节。以下是关于QMediaPlayer的一些关键点:
294 1
|
2月前
|
安全 C++ Windows
Windows下C++使用gRPC(Qt和VS,含文件包和使用方法)
Windows下C++使用gRPC(Qt和VS,含文件包和使用方法)
|
4月前
|
存储 网络协议 数据处理
【Socket】解决UDP丢包问题
UDP(用户数据报协议)是一种无连接的传输层协议,因其不保证数据包的顺序到达和不具备内置重传机制,导致在网络拥塞、接收缓冲区溢出或发送频率过快等情况下容易出现丢包现象。为应对这些问题,可以在应用层实现重传机制、使用前向纠错码等方法。这些方法在一定程度上可以缓解UDP通信中的丢包问题,提高数据传输的可靠性和效率。
|
3月前
基于QT实现的QQ聊天简易版(UDP通信版)
源码已经给小伙伴们整理好了,微信搜索 嵌入式工程之家 关注公众号回复 QQ 即可获得源码和详细操作指示哦~
|
3月前
|
Linux 开发者 iOS开发
QT:基于QMediaPlayer制作的视频播放器(最下方有整合包,可直接运行)
QMediaPlayer是Qt多媒体模块中的一个核心类,它提供了播放音频和视频内容的功能。这个类的设计旨在简化跨平台的媒体播放,使得开发者能够在多种操作系统(如Linux、Windows、macOS及移动平台)上轻松集成多媒体播放能力到他们的应用中,而无需关心底层实现细节。以下是关于QMediaPlayer的一些关键点:
|
11月前
|
安全 测试技术 C++
Windows下C++使用gRPC(Qt和VS,含文件包和使用方法)
最近用到了gRPC,配置了很长时间,分享一下配置过程。先来看一下我准备的文件包(资源我放在最后)
Windows下C++使用gRPC(Qt和VS,含文件包和使用方法)
|
5月前
|
网络协议 算法 网络架构
Python网络编程之udp编程、黏包以及解决方案、tcpserver
Python网络编程之udp编程、黏包以及解决方案、tcpserver
|
5月前
【DPDK 】dpdk测试发udp包
【DPDK 】dpdk测试发udp包
|
网络协议
Qt网络编程之搭建Udp通信【单播、组播、广播】
Qt网络编程之搭建Udp通信【单播、组播、广播】
780 0