UDP传输图片(分包)

2023-05-16

前提:需要了解QUdp的简单通信,比如收发个字符串

      QPixmap图片类,以此类来加载图片

      QBuffer和QByteArray来记录数据

      memcpy函数的用法

 

分包概念:举个例子就是客户端(C)给服务器(S)发送数据时,不一次性发送,而是将一个数据分成几份发送,然后在接收方将收到的数据再拼接在一起;比如:要发送字符串“123456789”给Server,我们可以先后发送“1”,“2”,“3”,“4”,“5”,“6”,“7”,“8”,“9”;在Server接收到数据后再拼接成“132456789”;

为了确定我们收到的是什么数据,是不是我们需要的数据:就需要定义一个报文头,来标识数据,使Server可以确定收到的数据是我们需要的;这时发送的数据格式就是:报文头+数据;报文头部分定义一些报文需要的参数,此处为例,根据需求增删改;

传输图片为例:将图片转换成QByte类型,然后分段,之后每次发送的数据就是:包头+其中一段数据;收到后,根据包头的信息,将数据段拼接成一个整体数据,然后再转成图片

struct PackageHeader

{
    unsigned int uTransPackageHdrSize; //包头大小

    unsigned int uTransPackageSize; //当前包大小

    unsigned int uDataSize; //数据总大小

    unsigned int uDataPackageNum; //数据被分成包的个数

    unsigned int uDataPackageCurrIndex; //数据包当前的帧号

    unsigned int uDataPackageOffset; //数据包在整个数据中的偏移
};

const int UDP_MAX_SIZE=1200;  //定义一个包发送的数据大小

//发送端的代码,memcpy不可用,需要根据具体操作来实现

void Widget::on_pushButton_clicked()

{
    QPixmap image("D:/splash.png");//定义要发送的图片

    QBuffer buffer;//借助QBuffer保存图片数据

    buffer.open(QIODevice::ReadWrite);

    image.save(&buffer,"jpg");

    int dataLength=buffer.data().size();//图片Byte大小,即表示图片大小

    unsigned char*dataBuffer=(unsigned char*)buffer.data().data();//将QByteArray数据类型转换

    int packetNum=0;//该图片一共分了多少个包发送

    int lastPaketSize=0;//最后一个包的大小

    packetNum=dataLength/UDP_MAX_SIZE;//UDP_MAX_SIZE定义一个包的大小

    lastPaketSize=dataLength%UDP_MAX_SIZE;//最后一个包的大小

    int currentPacketIndex=0;//当前包的ID

    if(lastPaketSize!=0)//如果最后一个包不是空,

    {

        packetNum=packetNum+1;//总包数+1,即数据不满1200也算一个包

    }

    PackageHeader packageHead;//定义一个包头,方便接收的时候区分

    packageHead.uTransPackageHdrSize=sizeof(packageHead);//包头大小

    packageHead.uDataSize=dataLength;//数据总大小

    packageHead.uDataPackageNum=packetNum;//图片被分成几个包发送

   

    while(currentPacketIndex<packetNum)//当前包的ID小于总的包数,说明没传完数据,即可以继续传

    {

        unsigned char frameBuffer[1024*1000];

        memset(frameBuffer,0,1024*1000);//清零

        

        if(currentPacketIndex<(packetNum-1))//数据量够UDP_MAX_SIZE的长度,也就是此时不是发的最后一个包

        {

            packageHead.uTransPackageSize=sizeof(PackageHeader)+UDP_MAX_SIZE;//当前包大小=包头大小+数据大小

            packageHead.uDataPackageCurrIndex=currentPacketIndex+1;//当前包ID默认是0,+1使开始ID为1

            packageHead.uDataPackageOffset=currentPacketIndex*UDP_MAX_SIZE;//偏移量

            memcpy(frameBuffer,&packageHead,sizeof(PackageHeader));//将包头赋值进容器

            memcpy(frameBuffer+sizeof(PackageHeader),dataBuffer+packageHead.uDataPackageOffset,UDP_MAX_SIZE);//将数据部分赋值给容器

            int length= sender->writeDatagram((const char*)frameBuffer,packageHead.uTransPackageSize,QHostAddress("192.168.0.28"),port);  //udp发送数据

            if(length!=packageHead.uTransPackageSize)

            {//length的值是UDP发送是否成功的判断

                qDebug()<<"Failed to send image";

            }

            currentPacketIndex++;

        }

        else//这个部分发送的是最后一个包,有可能是不够一个包长度的(1200)

        {//        当前包大小 (最后一个包的大小)       包头大小          + 剩余数据的大小

            packageHead.uTransPackageSize=sizeof(PackageHeader)+(dataLength-currentPacketIndex*UDP_MAX_SIZE);

            //                数据包当前的帧号

            packageHead.uDataPackageCurrIndex=currentPacketIndex+1;

            //数据包在整个数据中的偏移

            packageHead.uDataPackageOffset=currentPacketIndex*UDP_MAX_SIZE;

            memcpy(frameBuffer,&packageHead,sizeof(PackageHeader));//将包头赋值给char*

            //将数据体的一个包的长度赋值给cahr*

            memcpy(frameBuffer+sizeof(PackageHeader),dataBuffer+packageHead.uDataPackageOffset,dataLength-currentPacketIndex*UDP_MAX_SIZE);

            //UDP发送

            int length= sender->writeDatagram((const char*)frameBuffer,packageHead.uTransPackageSize,QHostAddress("192.168.0.28"),port);  //udp发送数据

            if(length!=packageHead.uTransPackageSize)

            {//length的值是UDP发送是否成功的判断

                qDebug()<<"Failed to send image";

            }

            currentPacketIndex++;

        }

    }

}

//接收端代码,memcpy不可用,需要根据需求自己改

QByteArray imageData;

void Widget::showText()

{

    while(receiver->hasPendingDatagrams())

    {

        QByteArray data;  data.clear();//准备接收容器

        data.resize(receiver->pendingDatagramSize());//指定容器大小

        receiver->readDatagram(data.data(),data.size()) ;//将数据赋值给容器

        static int num=1;

        static uint size=0;

        PackageHeader*packageHead=(PackageHeader*)data.data();//将包头部分先取出来

        if(packageHead->uDataPackageCurrIndex==num)//判断是否是第几个包

        {

            num++;

            //数据部分大小    =       当前包的大小   -  包头大小

            size+=packageHead->uTransPackageSize-packageHead->uTransPackageHdrSize;//当前包的大小-包头的大小=数据的大小

            if(size>1024*1000)

            {//如果当前包数据超过1024*1000,说明数据过大,不是需要的数据

                qDebug()<<"image too big";

                num=1;

                size=0;

                return;

            }

            if(packageHead->uDataPackageOffset>1024*1000)

            {//如果当前包数据偏移量超过1024*1000,说明数据过大,不是需要的数据

                qDebug()<<"image too big";

                packageHead->uDataPackageOffset=0;

                num=1;

                size=0;

                return;

            }

            memcpy(imageData.data+packageHead->uDataPackageOffset,data.data()+packageHead->uTransPackageHdrSize,

                   packageHead->uTransPackageSize-packageHead->uTransPackageHdrSize);//将数据部分赋值到数据容器里

            //确定数据传输完毕后,将数据转换成QPixmap类型

            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->label->setPixmap(pixmap);

                num=1;

                size=0;

            }

        }

        else

        {

            num=1;

            size=0;

            memset(&imageData,0,sizeof(UdpUnpackData));

        }

    }

}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UDP传输图片(分包) 的相关文章

  • Java UDP中如何获取实际数据包大小`byte[]`数组

    这是我上一个问题的后续问题 Java UDP发送 接收数据包一一接收 https stackoverflow com questions 21866382 java udp send receive packet one by one 正如
  • Android 上的 UDP 视频流

    我有一个 Android 项目 需要构建一个客户端应用程序来接收 UDP 或 RTP 单播视频流并播放它们 不幸的是 我似乎无法使其正常工作 并且已经广泛搜索了解决方案 我已经在 Xoom Android 3 2 和 Nexus S And
  • 具有多个接口的 Python UDP 套接字

    我正在 Windows XP 机器上用 python2 7 编写脚本 本机使用不同的网卡连接到多个网络 我遇到了一个问题 我已将 UDP 套接字绑定到特定接口 我知道您可以通过仅提供网卡现有的 IP 地址来在 Windows 中完成此操作
  • 错误的 UDP 校验和没有效果:为什么?

    我正在尝试测试 UDP 程序 如果它接收到 UDP 校验和错误的数据 会发生什么情况 奇怪的是 它似乎没有任何效果 并且有效负载被成功接收 至少在 OS X 上是通过环回接口成功接收的 下面是一个示例 其中使用以下方式发送数据SOCK RA
  • 用于接收 UDP 数据包的可变大小缓冲区

    我有一个 UDP 套接字 它将接收一些可能不同大小的数据包 并且我异步处理它 socket async receive from boost asio buffer buffer 65536 senderEndpoint handler 这
  • 接收来自 N 个客户端的响应,以回复通过 UDP 的广播请求

    我正在为特定类型的网络多媒体设备实现一种 IP 查找器 我想找出 LAN 中该类型的所有活动设备及其 IP 地址和其他详细信息 设备有自己的设备发现方式 其工作原理如下 客户端通过 UDP 通过 LAN 发送广播请求 目的端口号是固定的 作
  • 当网络上的所有计算机都具有相同的公共IP地址时,如何向特定计算机发送UDP数据包? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 这就是问题 它非常简单 理解 我家里有 2 台电脑 它们都有相同的公共 IP 地址 例如 1 2 3 4 我在咖啡馆有一台计算机 不同的网络 因此它具
  • C++ UDP Socket端口复用

    如何在 C 中创建客户端 UDP 套接字 以便它可以侦听另一个应用程序正在侦听的端口 换句话说 如何在 C 中应用端口复用 我只想监听一个端口 您可以使用嗅探器来做到这一点 只需忽略来自不同端口的数据包即可 我可能需要阻止它发送一些特定的数
  • Windows 操作系统中无法访问的 IP 套接字关闭时间

    这些代码通过用户数据报协议提供发送数据 下面有两个代码 当我使用第一个代码来处理无法访问的 IP 地址时 我得到了三秒的延迟 请查看新结果标题 只需打开新的 C 控制台应用程序并将这些代码粘贴到其中 第一个代码 using System u
  • 为什么我们可以将 sockaddr 转换为 sockaddr_in

    我明白为什么强制转换很有用sockaddr to sockaddr in 但我不明白这怎么可能 据我所知 它们的大小相同sockaddr in添加了sin zero使其大小相同 我想知道编译器如何知道从哪里获取信息sockaddr in如果
  • 提高UDP可靠性

    我正在构建一个基于 UDP 的小型服务器 服务器基于 Net并使用它自己的Socket类 我通过 ReceiveMessageFromAsync 和异步发送使用完成端口 我的问题是我失去了大约 5 10 的流量 现在我明白这是正常的 但是有
  • F1 2019 UDP解码

    我目前正在为 F1 方向盘开发自己的显示器 F1 2019 由codemasters提供 通过UDP发送数据 该数据存储在字节数组中 我在解码返回的数组时遇到一些问题 问题是我得到了很多信息 但我不知道如何处理它们 我将向您介绍我所尝试过的
  • 在 PowerShell 中通过 UDP 发送和接收数据

    我正在尝试编写一个脚本来使用 PowerShell 进行测试和应用 测试应包括通过 UDP 向远程服务器发送字符串 然后读取该服务器的响应并对结果执行某些操作 我需要的唯一帮助是脚本的中间两个步骤 发送字符串 然后 接收响应 在端口 UDP
  • 使用 Boost.Asio 进行广播的问题

    如果问题之前已得到解答 我提前表示歉意 但我已经搜索并没有找到任何对我有帮助的东西 正如问题标题所示 我正在尝试将包从服务器广播到一组侦听任何消息的客户端 客户端将计算一秒钟内收到的消息数 服务器端的事情是这样的 class Server
  • UDP 广播发送失败:在 Linux 2.6.30 上“网络无法访问”

    我用udp广播写了一个程序 代码段如下 struct sockaddr in broadcast addr socklen t sock len sizeof broadcast addr bzero broadcast addr sock
  • Node.js 可读流_read用法

    我了解如何在 Node 的 new 中使用可写流Streams2库 但我不明白如何使用可读流 举个例子 一个流包装器围绕dgram module var dgram require dgram var thumbs twiddle func
  • 为什么SOCKS5需要通过UDP中继UDP?

    The SOCKS5 https en wikipedia org wiki SOCKS SOCKS5协议 描述为RFC1928 https www rfc editor org rfc rfc1928提供对 UDP 的支持 总而言之 希望
  • 写入 UDP 套接字会被阻塞吗?

    如果是的话 在什么条件下 或者 换句话说 在twisted 中运行此代码是否安全 class StatsdClient AbstractStatsdClient def init self host port super StatsdCli
  • RTSP 设置后接收 RTP 数据包

    我正在尝试使用 Python 从 IP 摄像机流式传输 RTP 数据包 我能够使用 RTSP 协议发送描述 设置和播放命令 但是 我无法开始使用 RTP 传输实际视频流 这是代码 import socket def printrec rec
  • Netty UDP 服务器中的线程未同时执行

    我正在分析的代码使用 Netty NioDatagramChannelFactory 创建 UDP 服务器 它创建一个线程池 ExecutorService threadPool Executors newCachedThreadPool

随机推荐