当前位置:   article > 正文

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

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

前言

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

注意:

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

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

        

发送端:

main.cpp

  1. #include <QUdpSocket>
  2. #include <QtEndian>
  3. #include <QDataStream>
  4. // 以1字节对齐:
  5. #pragma pack(1)
  6. struct SaveVideoCtrlPara
  7. {
  8. // 帧头 0xaa56
  9. unsigned short dataHead = 0xbb58;
  10. // 第一路
  11. quint8 video1_isSave = 0x00; // 0x00:close 0x01:start save
  12. quint8 video1_type = 0x00; // 0x00:null 0x01:rtsp 0x02:rtp
  13. quint32 video1_para = 0x00; // rtsp: IP rtp :recv port
  14. quint32 video1_reserve = 0x00; // 预留
  15. char video1_fileName[64] = ""; // 保存文件名
  16. // 第一路
  17. quint8 video2_isSave = 0x00; // 0x00:close 0x01:start save
  18. quint8 video2_type = 0x00; // 0x00:null 0x01:rtsp 0x02:rtp
  19. quint32 video2_para = 0x00; // rtsp: IP rtp :recv port
  20. quint32 video2_reserve = 0x00; // 预留
  21. char video2_fileName[64] = ""; // 保存文件名
  22. // 包尾
  23. // unsigned short dataTail = 0x1111;
  24. };
  25. #pragma pack(pop)
  26. // 转为大端序
  27. QByteArray serializeStruct(const SaveVideoCtrlPara &data) {
  28. QByteArray byteArray;
  29. QDataStream stream(&byteArray, QIODevice::WriteOnly);
  30. // 将数据转换为大端序
  31. stream << qToBigEndian(data.dataHead);
  32. stream << qToBigEndian(data.video1_isSave);
  33. stream << qToBigEndian(data.video1_type);
  34. stream << qToBigEndian(data.video1_para);
  35. stream << qToBigEndian(data.video1_reserve);
  36. stream << QString(data.video1_fileName).toUtf8();
  37. stream << qToBigEndian(data.video2_isSave);
  38. stream << qToBigEndian(data.video2_type);
  39. stream << qToBigEndian(data.video2_para);
  40. stream << qToBigEndian(data.video2_reserve);
  41. stream << QString(data.video2_fileName).toUtf8();
  42. return byteArray;
  43. }
  44. int main(int argc, char *argv[])
  45. {
  46. QByteArray temp_byte_array;
  47. SaveVideoCtrlPara test;
  48. test.video1_type = 0x02;
  49. test.video1_para = 10011;
  50. strcpy(test.video1_fileName,"test1");
  51. test.video2_type = 0x02;
  52. test.video2_para = 10012;
  53. strcpy(test.video2_fileName,"test2");
  54. QUdpSocket *m_pUdpSocket = new QUdpSocket();
  55. m_pUdpSocket->bind(QHostAddress("127.0.0.1"),18001);
  56. // 小端序
  57. // QByteArray frame = QByteArray((char *)&test, sizeof(SaveVideoCtrlPara));
  58. // 大端序
  59. QByteArray frame = serializeStruct(test);
  60. // send
  61. m_pUdpSocket->writeDatagram(frame, QHostAddress("127.0.0.1"), 18000);
  62. }

接收端:

main.cpp

  1. #include <QApplication>
  2. #include <QUdpSocket>
  3. #include <QDataStream>
  4. #include <QtEndian>
  5. // 以1字节对齐:
  6. #pragma pack(1)
  7. struct SaveVideoCtrlPara
  8. {
  9. // 帧头 0xaa56
  10. unsigned short dataHead = 0xbb58;
  11. // 第一路
  12. quint8 video1_isSave = 0x00; // 0x00:close 0x01:start save
  13. quint8 video1_type = 0x00; // 0x00:null 0x01:rtsp 0x02:rtp
  14. quint32 video1_para = 0x00; // rtsp: IP rtp :recv port
  15. quint32 video1_reserve = 0x00; // 预留
  16. char video1_fileName[64] = ""; // 保存文件名
  17. // 第一路
  18. quint8 video2_isSave = 0x00; // 0x00:close 0x01:start save
  19. quint8 video2_type = 0x00; // 0x00:null 0x01:rtsp 0x02:rtp
  20. quint32 video2_para = 0x00; // rtsp: IP rtp :recv port
  21. quint32 video2_reserve = 0x00; // 预留
  22. char video2_fileName[64] = ""; // 保存文件名
  23. // 包尾
  24. // unsigned short dataTail = 0x1111;
  25. };
  26. #pragma pack(pop)
  27. SaveVideoCtrlPara deserializeStruct(const QByteArray &byteArray)
  28. {
  29. QDataStream stream(byteArray);
  30. QByteArray tmp_str1,tmp_str2;
  31. //tmp_str1.resize(64);
  32. //tmp_str2.resize(64);
  33. stream.setByteOrder(QDataStream::BigEndian); // 设置为大端序
  34. SaveVideoCtrlPara data;
  35. // 从数据流中读取并转换为小端序
  36. stream >> data.dataHead;
  37. stream >> data.video1_isSave;
  38. stream >> data.video1_type;
  39. stream >> data.video1_para;
  40. stream >> data.video1_reserve;
  41. stream >> tmp_str1;
  42. stream >> data.video2_isSave;
  43. stream >> data.video2_type;
  44. stream >> data.video2_para;
  45. stream >> data.video2_reserve;
  46. stream >> tmp_str2;
  47. data.dataHead = qFromBigEndian(data.dataHead);
  48. data.video1_isSave = qFromBigEndian(data.video1_isSave);
  49. data.video1_type = qFromBigEndian(data.video1_type);
  50. data.video1_para = qFromBigEndian(data.video1_para);
  51. data.video1_reserve = qFromBigEndian(data.video1_reserve);
  52. strcpy(data.video1_fileName, tmp_str1.toStdString().c_str());
  53. data.video2_isSave = qFromBigEndian(data.video2_isSave);
  54. data.video2_type = qFromBigEndian(data.video2_type);
  55. data.video2_para = qFromBigEndian(data.video2_para);
  56. data.video2_reserve = qFromBigEndian(data.video2_reserve);
  57. strcpy(data.video2_fileName, tmp_str2.toStdString().c_str());
  58. return data;
  59. }
  60. int main(int argc, char *argv[])
  61. {
  62. QApplication app(argc, argv);
  63. QUdpSocket *m_pUdpSocket = new QUdpSocket();
  64. m_pUdpSocket->bind(QHostAddress("127.0.0.1"),18000);
  65. QObject::connect(m_pUdpSocket,&QUdpSocket::readyRead,[=](){
  66. QByteArray frame;
  67. while(m_pUdpSocket->hasPendingDatagrams())
  68. {
  69. frame.resize(m_pUdpSocket->pendingDatagramSize());
  70. // 接收数据报,将其存放到datagram中
  71. m_pUdpSocket->readDatagram(frame.data(), frame.size());
  72. // 大端序
  73. SaveVideoCtrlPara pFrame = deserializeStruct(frame);
  74. if(pFrame.dataHead == 0xaa56)
  75. {
  76. qDebug()<<"接收到信息*********";
  77. qDebug()<<"video1_isSave:" <<pFrame.video1_isSave;
  78. qDebug()<<"video1_type :" <<pFrame.video1_type ;
  79. if(pFrame.video1_type==0x01)
  80. qDebug()<<"video1_para :" <<QHostAddress(pFrame.video1_para).toString();
  81. else
  82. qDebug()<<"video1_para :" <<pFrame.video1_para;
  83. qDebug()<<"video1_fileName:"<<pFrame.video1_fileName;
  84. qDebug()<<"video2_isSave:" <<pFrame.video2_isSave;
  85. qDebug()<<"video2_type :" <<pFrame.video2_type ;
  86. if(pFrame.video2_type==0x01)
  87. qDebug()<<"video2_para :" <<QHostAddress(pFrame.video2_para).toString();
  88. else
  89. qDebug()<<"video2_para :" <<pFrame.video2_para;
  90. qDebug()<<"video2_fileName:"<<pFrame.video2_fileName;
  91. qDebug()<<"*****************";
  92. }
  93. // // 小端序
  94. // struct SaveVideoCtrlPara *pFrame = (struct SaveVideoCtrlPara *)frame.data();
  95. // if(pFrame->dataHead == 0xaa56)
  96. // {
  97. // qDebug()<<"接收到信息*********";
  98. // qDebug()<<"video1_isSave:" <<pFrame->video1_isSave;
  99. // qDebug()<<"video1_type :" <<pFrame->video1_type ;
  100. // if(pFrame->video1_type==0x01)
  101. // qDebug()<<"video1_para :" <<QHostAddress(pFrame->video1_para).toString();
  102. // else
  103. // qDebug()<<"video1_para :" <<pFrame->video1_para;
  104. // qDebug()<<"video1_fileName:"<<pFrame->video1_fileName;
  105. // qDebug()<<"video2_isSave:" <<pFrame->video2_isSave;
  106. // qDebug()<<"video2_type :" <<pFrame->video2_type ;
  107. // if(pFrame->video2_type==0x01)
  108. // qDebug()<<"video2_para :" <<QHostAddress(pFrame->video2_para).toString();
  109. // else
  110. // qDebug()<<"video2_para :" <<pFrame->video2_para;
  111. // qDebug()<<"video2_fileName:"<<pFrame->video2_fileName;
  112. // qDebug()<<"*****************";
  113. // }
  114. }
  115. });
  116. return app.exec();
  117. }

结论

大端序代码打印结果:

小端序代码打印结果:

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/789701
推荐阅读
相关标签
  

闽ICP备14008679号