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++的学习,希望一切顺利。

相关文章
|
4天前
|
网络协议 算法 网络架构
Python网络编程之udp编程、黏包以及解决方案、tcpserver
Python网络编程之udp编程、黏包以及解决方案、tcpserver
|
4天前
【DPDK 】dpdk测试发udp包
【DPDK 】dpdk测试发udp包
|
11月前
|
缓存 网络协议 算法
【Python基础篇021】黏包现象丨udp的socket服务
【Python基础篇021】黏包现象丨udp的socket服务
10930 0
|
自然语言处理 安全 网络协议
TCP/UDP常见端口参考(超全_面试题常用_建议收藏)(4)
TCP/UDP常见端口参考(超全_面试题常用_建议收藏)(4)
186 0
|
安全 网络协议 Unix
TCP/UDP常见端口参考(超全_面试题常用_建议收藏)(3)
TCP/UDP常见端口参考(超全_面试题常用_建议收藏)(3)
139 0
|
网络协议 安全 Unix
TCP/UDP常见端口参考(超全_面试题常用_建议收藏)(2)
TCP/UDP常见端口参考(超全_面试题常用_建议收藏)(2)
127 0
|
网络协议 安全 前端开发
TCP/UDP常见端口参考(超全_面试题常用_建议收藏)(1)
TCP/UDP常见端口参考(超全_面试题常用_建议收藏)(1)
109 0
|
网络协议 网络性能优化 安全
用户数据包协议(user datagram protocol)——UDP
用户数据报协议(User Datagram Protocol,UDP)是无连接不可靠传输层协议。它不提供主机到主机通信,它除了提供进程到进程之间的通信之外,就没有给 IP 服务增加任何东西。
1512 0