做直播网站视频教程,福田网站建设推荐,合肥seo网站推广,游戏app软件开发公司前言 虽然QT中#xff0c;udp发送和接收#xff0c;其实非常简单#xff0c;但是实际工作中#xff0c;其实涉及到帧头帧尾#xff0c;字节对齐#xff0c;以及大小端序的问题。比如网络中#xff0c;正规的一般都是大端序#xff0c;而不是小端序#xff0c;大多数的…前言 虽然QT中udp发送和接收其实非常简单但是实际工作中其实涉及到帧头帧尾字节对齐以及大小端序的问题。比如网络中正规的一般都是大端序而不是小端序大多数的系统中默认存储的都是小端序。 其次udp指令在代码中我们一般都会设置结构体如果是小端可以直接使用结果体转换如果是大端序需要先将数据转尾大端然后发送接收端再将大端序数据转为小端进行分析和保存。以下是一个实际案例的测试demo
注意 以下协议和帧头等都是根据近期项目随机定的不涉及保密。 指令接收端口为18000 目的是开启视频保存。 发送端
main.cpp #include QUdpSocket
#include QtEndian
#include QDataStream// 以1字节对齐
#pragma pack(1)
struct SaveVideoCtrlPara
{// 帧头 0xaa56unsigned short dataHead 0xbb58;// 第一路quint8 video1_isSave 0x00; // 0x00:close 0x01:start savequint8 video1_type 0x00; // 0x00:null 0x01:rtsp 0x02:rtpquint32 video1_para 0x00; // rtsp: IP rtp :recv portquint32 video1_reserve 0x00; // 预留char video1_fileName[64] ; // 保存文件名// 第一路quint8 video2_isSave 0x00; // 0x00:close 0x01:start savequint8 video2_type 0x00; // 0x00:null 0x01:rtsp 0x02:rtpquint32 video2_para 0x00; // rtsp: IP rtp :recv portquint32 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);// sendm_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
{// 帧头 0xaa56unsigned short dataHead 0xbb58;// 第一路quint8 video1_isSave 0x00; // 0x00:close 0x01:start savequint8 video1_type 0x00; // 0x00:null 0x01:rtsp 0x02:rtpquint32 video1_para 0x00; // rtsp: IP rtp :recv portquint32 video1_reserve 0x00; // 预留char video1_fileName[64] ; // 保存文件名// 第一路quint8 video2_isSave 0x00; // 0x00:close 0x01:start savequint8 video2_type 0x00; // 0x00:null 0x01:rtsp 0x02:rtpquint32 video2_para 0x00; // rtsp: IP rtp :recv portquint32 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_type0x01)qDebug()video1_para : QHostAddress(pFrame.video1_para).toString();elseqDebug()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_type0x01)qDebug()video2_para : QHostAddress(pFrame.video2_para).toString();elseqDebug()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_type0x01)
// 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_type0x01)
// 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();
}结论
大端序代码打印结果 小端序代码打印结果 由代码可知大端序要稍微复杂一些但是符合互联网传输数据的要求小端序的实现要简单不少所以如果是非正规场合使用小端是一种简洁的方式。