Qt中udp指令,大小端,帧头帧尾实际示例

news2024/10/7 9:17:34

前言

        虽然QT中,udp发送和接收,其实非常简单,但是实际工作中,其实涉及到帧头帧尾,字节对齐,以及大小端序的问题。比如网络中,正规的一般都是大端序,而不是小端序,大多数的系统中,默认存储的都是小端序。 其次,udp指令,在代码中,我们一般都会设置结构体,如果是小端可以直接使用结果体转换,如果是大端序,需要先将数据转尾大端然后发送,接收端再将大端序数据转为小端进行分析和保存。以下是一个实际案例的测试demo:

注意:

        以下协议和帧头等都是根据近期项目随机定的,不涉及保密。

        指令接收端口为18000; 目的是开启视频保存。

        

发送端:

main.cpp


#include <QUdpSocket>
#include <QtEndian>
#include <QDataStream>

// 以1字节对齐:
#pragma pack(1)
struct SaveVideoCtrlPara
{
    // 帧头 0xaa56
    unsigned short dataHead = 0xbb58;

    // 第一路
    quint8    video1_isSave       = 0x00;       // 0x00:close    0x01:start save
    quint8    video1_type         = 0x00;       // 0x00:null     0x01:rtsp        0x02:rtp
    quint32   video1_para         = 0x00;       // rtsp: IP      rtp :recv port
    quint32   video1_reserve      = 0x00;       // 预留
    char      video1_fileName[64] = "";         // 保存文件名

    // 第一路
    quint8    video2_isSave       = 0x00;       // 0x00:close    0x01:start save
    quint8    video2_type         = 0x00;       // 0x00:null     0x01:rtsp        0x02:rtp
    quint32   video2_para         = 0x00;       // rtsp: IP      rtp :recv port
    quint32   video2_reserve      = 0x00;       // 预留
    char      video2_fileName[64] = "";         // 保存文件名

    // 包尾
    // unsigned short dataTail = 0x1111;
};
#pragma pack(pop)

// 转为大端序
QByteArray serializeStruct(const SaveVideoCtrlPara &data) {
    QByteArray byteArray;
    QDataStream stream(&byteArray, QIODevice::WriteOnly);

    // 将数据转换为大端序
    stream << qToBigEndian(data.dataHead);
    stream << qToBigEndian(data.video1_isSave);
    stream << qToBigEndian(data.video1_type);
    stream << qToBigEndian(data.video1_para);
    stream << qToBigEndian(data.video1_reserve);
    stream << QString(data.video1_fileName).toUtf8();

    stream << qToBigEndian(data.video2_isSave);
    stream << qToBigEndian(data.video2_type);
    stream << qToBigEndian(data.video2_para);
    stream << qToBigEndian(data.video2_reserve);
    stream << QString(data.video2_fileName).toUtf8();

    return byteArray;
}

int main(int argc, char *argv[])
{

    QByteArray temp_byte_array;
    SaveVideoCtrlPara test;

    test.video1_type = 0x02;
    test.video1_para = 10011;
    strcpy(test.video1_fileName,"test1");
    test.video2_type = 0x02;
    test.video2_para = 10012;
    strcpy(test.video2_fileName,"test2");

    QUdpSocket *m_pUdpSocket = new QUdpSocket();
    m_pUdpSocket->bind(QHostAddress("127.0.0.1"),18001);
    
    // 小端序
    // QByteArray frame = QByteArray((char *)&test, sizeof(SaveVideoCtrlPara));
    
    // 大端序
    QByteArray frame = serializeStruct(test);
    
    // send
    m_pUdpSocket->writeDatagram(frame, QHostAddress("127.0.0.1"), 18000);

}

接收端:

main.cpp

#include <QApplication>
#include <QUdpSocket>
#include <QDataStream>
#include <QtEndian>

// 以1字节对齐:
#pragma pack(1)
struct SaveVideoCtrlPara
{
    // 帧头 0xaa56
    unsigned short dataHead = 0xbb58;

    // 第一路
    quint8    video1_isSave       = 0x00;       // 0x00:close    0x01:start save
    quint8    video1_type         = 0x00;       // 0x00:null     0x01:rtsp        0x02:rtp
    quint32   video1_para         = 0x00;       // rtsp: IP      rtp :recv port
    quint32   video1_reserve      = 0x00;       // 预留
    char      video1_fileName[64] = "";         // 保存文件名

    // 第一路
    quint8    video2_isSave       = 0x00;       // 0x00:close    0x01:start save
    quint8    video2_type         = 0x00;       // 0x00:null     0x01:rtsp        0x02:rtp
    quint32   video2_para         = 0x00;       // rtsp: IP      rtp :recv port
    quint32   video2_reserve      = 0x00;       // 预留
    char      video2_fileName[64] = "";         // 保存文件名

    // 包尾
    // unsigned short dataTail = 0x1111;
};
#pragma pack(pop)

SaveVideoCtrlPara deserializeStruct(const QByteArray &byteArray)
{
    QDataStream stream(byteArray);
    QByteArray tmp_str1,tmp_str2;
    //tmp_str1.resize(64);
    //tmp_str2.resize(64);
    stream.setByteOrder(QDataStream::BigEndian); // 设置为大端序

    SaveVideoCtrlPara data;

    // 从数据流中读取并转换为小端序
    stream >> data.dataHead;
    stream >> data.video1_isSave;
    stream >> data.video1_type;
    stream >> data.video1_para;
    stream >> data.video1_reserve;
    stream >> tmp_str1;

    stream >> data.video2_isSave;
    stream >> data.video2_type;
    stream >> data.video2_para;
    stream >> data.video2_reserve;
    stream >> tmp_str2;

    data.dataHead = qFromBigEndian(data.dataHead);
    data.video1_isSave = qFromBigEndian(data.video1_isSave);
    data.video1_type = qFromBigEndian(data.video1_type);
    data.video1_para = qFromBigEndian(data.video1_para);
    data.video1_reserve = qFromBigEndian(data.video1_reserve);
    strcpy(data.video1_fileName, tmp_str1.toStdString().c_str());

    data.video2_isSave = qFromBigEndian(data.video2_isSave);
    data.video2_type = qFromBigEndian(data.video2_type);
    data.video2_para = qFromBigEndian(data.video2_para);
    data.video2_reserve = qFromBigEndian(data.video2_reserve);
    strcpy(data.video2_fileName, tmp_str2.toStdString().c_str());

    return data;
}


int main(int argc, char *argv[])
{

    QApplication app(argc, argv);
    QUdpSocket *m_pUdpSocket = new QUdpSocket();
    m_pUdpSocket->bind(QHostAddress("127.0.0.1"),18000);
    QObject::connect(m_pUdpSocket,&QUdpSocket::readyRead,[=](){
        QByteArray frame;
        while(m_pUdpSocket->hasPendingDatagrams())
        {
            frame.resize(m_pUdpSocket->pendingDatagramSize());
            // 接收数据报,将其存放到datagram中
            m_pUdpSocket->readDatagram(frame.data(), frame.size());

            // 大端序
            SaveVideoCtrlPara pFrame = deserializeStruct(frame);
            if(pFrame.dataHead == 0xaa56)
            {
                qDebug()<<"接收到信息*********";
                qDebug()<<"video1_isSave:"  <<pFrame.video1_isSave;
                qDebug()<<"video1_type  :"  <<pFrame.video1_type  ;
                if(pFrame.video1_type==0x01)
                    qDebug()<<"video1_para  :"  <<QHostAddress(pFrame.video1_para).toString();
                else
                    qDebug()<<"video1_para  :"  <<pFrame.video1_para;

                qDebug()<<"video1_fileName:"<<pFrame.video1_fileName;

                qDebug()<<"video2_isSave:"  <<pFrame.video2_isSave;
                qDebug()<<"video2_type  :"  <<pFrame.video2_type  ;
                if(pFrame.video2_type==0x01)
                    qDebug()<<"video2_para  :"  <<QHostAddress(pFrame.video2_para).toString();
                else
                    qDebug()<<"video2_para  :"  <<pFrame.video2_para;
                qDebug()<<"video2_fileName:"<<pFrame.video2_fileName;
                qDebug()<<"*****************";
            }

//            // 小端序
//            struct SaveVideoCtrlPara *pFrame = (struct SaveVideoCtrlPara *)frame.data();
//            if(pFrame->dataHead == 0xaa56)
//            {
//                qDebug()<<"接收到信息*********";
//                qDebug()<<"video1_isSave:"  <<pFrame->video1_isSave;
//                qDebug()<<"video1_type  :"  <<pFrame->video1_type  ;
//                if(pFrame->video1_type==0x01)
//                    qDebug()<<"video1_para  :"  <<QHostAddress(pFrame->video1_para).toString();
//                else
//                    qDebug()<<"video1_para  :"  <<pFrame->video1_para;
//                qDebug()<<"video1_fileName:"<<pFrame->video1_fileName;

//                qDebug()<<"video2_isSave:"  <<pFrame->video2_isSave;
//                qDebug()<<"video2_type  :"  <<pFrame->video2_type  ;
//                if(pFrame->video2_type==0x01)
//                    qDebug()<<"video2_para  :"  <<QHostAddress(pFrame->video2_para).toString();
//                else
//                    qDebug()<<"video2_para  :"  <<pFrame->video2_para;
//                qDebug()<<"video2_fileName:"<<pFrame->video2_fileName;
//                qDebug()<<"*****************";
//            }
        }
    });

    return app.exec();
}

结论

大端序代码打印结果:

小端序代码打印结果:

        由代码可知,大端序要稍微复杂一些,但是符合互联网传输数据的要求,小端序的实现要简单不少,所以如果是非正规场合,使用小端是一种简洁的方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1892064.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024鲲鹏昇腾创新大赛集训营Ascend C算子学习笔记

异构计算架构&#xff08;CANN&#xff09; 对标英伟达的CUDA CuDNN的核心软件层&#xff0c;向上支持多种AI框架&#xff0c;向下服务AI处理器&#xff0c;发挥承上启下的关键作用&#xff0c;是提升昇腾AI处理器计算效率的关键平台。主要包括有各种引擎、编译器、执行器、算…

mac磁盘工具如何合并分区 macos 磁盘工具 无法抹除 磁盘管理软件哪个使用率最高

一、什么是NTFS格式分区 NTFS格式分区是微软公司开发的诸多文件系统中的一种。NTFS格式分区是一种文件系统&#xff0c;磁盘只有在安装了文件系统后才能被正常使用&#xff0c;文件系统的格式有非常多&#xff0c;常见的有FAT 32和NTFS。 作为常见文件系统&#xff0c;NTFS格式…

Conmi的正确答案——ESP32-C3开启安全下载模式

IDF版本&#xff1a;4.4.7 注意事项&#xff1a;一旦烧录“安全下载模式”&#xff0c;模组将无法被读取或清理&#xff0c;只能通过eclipse原项目烧录程序进行重新烧录&#xff0c;无法再烧录其他固件。 20240703110201——追加解法&#xff0c;暂时无法解安全下载模式 &…

Python数据分析-股票数据分析(GARCH模型)

一、研究背景 随着金融市场的不断发展和全球经济的日益复杂&#xff0c;市场波动性和风险管理成为投资者和金融机构关注的焦点。波动率是衡量市场风险的重要指标&#xff0c;准确预测和评估波动率对于资产定价、风险控制和投资决策具有重要意义。在金融时间序列分析中&#xf…

上海会议论坛可以邀请哪些媒体?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 上海会议论坛可以邀请的媒体包括电视媒体、报纸媒体、网络媒体、视频媒体以及专业的媒体邀约机构。具体介绍如下&#xff1a; 电视媒体&#xff1a;上海的第一财经频道和东方财经频道等&…

《python程序语言设计》2018版第5章第51题利用turtle画18x18的格子

05.51.01version 先从第一一个格子来做 turtle.right(45) turtle.circle(18, steps4) turtle.hideturtle() turtle.done()这个代码很简单的现实出格子的样式。 现在的问题是循环的话。首先角度45度怎么处理 随着45度一次一次迭代。他是应该转4590呢还是4545呢&#xff1f;&…

【Mac】Boxy SVG for Mac(矢量图编辑器)及同类型软件介绍

软件介绍 Boxy SVG 是一款功能强大的矢量图形编辑器&#xff0c;专门为 macOS 平台设计开发。它主要用于创建和编辑 SVG&#xff08;可缩放矢量图形&#xff09;文件&#xff0c;是设计师和开发者们制作矢量图形的理想工具。 以下是关于 Boxy SVG 的主要特点和功能&#xff1a…

权限维持Linux---监控功能Strace后门命令自定义Alias后门

免责声明:本文仅做技术交流与学习... 目录 监控功能Strace后门 1、记录 sshd 明文 监控 筛选查看 2、记录sshd私钥 命令自定义Alias后门 1、简单粗鲁实现反弹&#xff1a; 靶机替换命令 攻击机监听上线 2.升级(让命令正常) 将反弹命令进行base64编码 替换alias命令 …

使用本地部署的Hermes 2 Pro构建开放的LLM应用程序

之前我介绍了如何使用OpenAI最新的LLM GPT-4o&#xff0c;通过函数调用将实时数据引入到LLM。在这篇后续文章中我将介绍使用Hermes 2 Pro -Llama- 3 8B进行函数调用&#xff0c;这是一种由Nous Research开发的功能强大的LLM&#xff0c;基于Meta的Llama 3架构&#xff0c;有80亿…

解锁Diffusion Model: 初识Stable Diffusion、DALL-E、Imagen

------->更多内容&#xff0c;请移步“鲁班秘笈”&#xff01;&#xff01;<------- 扩散模型在生成高质量图像、视频、声音等方面表现突出。它们与物理学中的自然扩散过程相似而得名&#xff0c;自然扩散过程描述了分子如何从高浓度区域移动到低浓度区域。在机器学习的…

【Python】已解决:ModuleNotFoundError: No module named ‘cv2’

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;ModuleNotFoundError: No module named ‘cv2’ 一、分析问题背景 在Python编程中&#xff0c;当你尝试导入一个不存在的模块时&#xff0c;会遇到ModuleNotFou…

公有链、私有链与联盟链:区块链技术的多元化应用与比较

引言 区块链技术自2008年比特币白皮书发布以来&#xff0c;迅速发展成为一项具有颠覆性潜力的技术。区块链通过去中心化、不可篡改和透明的方式&#xff0c;提供了一种全新的数据存储和管理方式。起初&#xff0c;区块链主要应用于加密货币&#xff0c;如比特币和以太坊。然而&…

Vue84-Vuex的工作原理与搭建开发环境

一、vuex工作原理 stats&#xff1a;是一个object对象&#xff0c;里面有很多key-value&#xff0c;存放的就是要操作的数据。mutations&#xff1a;是一个object对象&#xff0c;真正去操作stats的人。actions的作用&#xff1a;是一个object对象&#xff0c;当一个动作对应的…

力扣Hot100-24两两交换链表中的节点(三指针)

给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4] 输出&#xff1a;[2,1,4…

VirtualBox 虚拟机的网络通过宿主机的网络进行冲浪

虚拟机与宿主机通过桥接模式处在同一个网络中 1.说明2.操作步骤2.1.虚拟机设置网络2.2.手动指定虚拟机的IP 1.说明 A.虚拟机 ubuntu-20.04 B.宿主机网络 Wireless LAN adapter WLAN:Connection-specific DNS Suffix . : lanIPv4 Address. . . . . . . . . . . : 192.168.111…

MYSQL的简易安装

先下载好安装包 官网&#xff1a;https://www.mysql.com 双击运行进入界面 打开之后将左侧的产品移到右侧 点击使用的产品设置路径 之后一直下一步即可 选择主机类型 同时要记住端口号 设置密码 设置系统服务列表中的服务名称 之后一直下一步就可以了 安装完成记得配置环…

AUTOSAR NvM模块(七)

NvM工具配置demo 一切block的配置根据自己的需求&#xff01; NvMBlockDescriptor NvM Common MemIf General FeeBlockConfiguration FeeGeneral

CASS中按指定距离和方向移动图形

1、绘制一个图形 打开软件&#xff0c;随意绘制一个矩形&#xff0c;并量取左下角点的坐标值&#xff0c;具体如下&#xff1a; 2、按距离移动原理讲解 例1&#xff1a;将图形沿着y轴负方向移动100米&#xff0c;如何实现&#xff1f; 如上图所示&#xff0c;测绘中的坐标系…

【FPGA】STA静态时序分析

文章目录 一.定义二.分类1. 静态时序分析2. 静态时序分析 三. 概念四. 时间余量1.场景2.建立时间余量3.保持时间余量 一.定义 时序分析:检查电路是否满足时序要求&#xff1b; 二.分类 1. 静态时序分析 STA,遍历所有的时序路径&#xff0c;根据时序库&#xff08;.lib文件&…

基于Java中的SSM框架实现物流管理系统项目【项目源码+论文说明】

基于Java中的SSM框架实现物流管理系统演示 摘要 企业的发展离不开物流的运输&#xff0c;在一个大型的企业中&#xff0c;商品的生产和建设&#xff0c;推广只是前期的一些工作&#xff0c;在后期的商品销售和物流方面的建立&#xff0c;才能让一个企业得到大力的发展。 企业…