UDP传送和接受结构体结构的消息 | 您所在的位置:网站首页 › qt序列化结构体 › UDP传送和接受结构体结构的消息 |
前言
最近的项目用到UDP接收结构体,以为和普通的传送字符串的一样,没想到我还是太天真。要能够接收或者传送结构体,一个很重要的知识点是:结构体字节对齐。废话不多说,小课堂开始了! 结构体对齐参考https://www.cnblogs.com/codingnutter/p/5634482.html 许多计算机系统对基本数据类型合法的进行了一些限制,要求某种类型对象的地址必须是某个值(通常是2,4 和8)的倍数。这种对齐简化了形成处理器与存储系统之间的接口的硬件设计。当数据结构为结构体时,为了满足这种数据对齐的机制,编译器可能需要在结构体的字段的分配中插入间隙--向结构体中最大的元素对齐。 typedef struct { char c; int i[2]; double v; }S;看上面的结构体,在没有数据对齐的情况下,size()=1+4*2+8=17字节。 再编译器数据对齐处理后,他的结构大小变成了24字节(向结构体中最大的元素对齐),内存布局为 这个就是为什么我强转后,结构体中的部分数据是乱码的。 改进后(结构体一字节对齐)在听取网友意见后,发现将结构体一字节对齐后,操作真的是非常简单。 结构体一字节对齐: #pragma pack(1) //指定一字节对齐 struct Test_data{ int iNumber; char arrchResult[45]; char arrchCode[12]; bool bOutLimit_Flag; int iMark; BYTE byteResultType; }; #pragma pack() //取消指定对齐,恢复缺省对齐直接发送或接收 data.iNumber=1; strcpy(data.arrchResult,"hello"); strcpy(data.arrchCode,"0x29"); data.bOutLimit_Flag=true; data.iMark=200; data.byteResultType=23; //发送 udpSocket->writeDatagram((char *)&data,sizeof(data),QHostAddress::Broadcast,port); Test_data datagram; //接收 udpSocket->readDatagram((char*)&datagram,sizeof(datagram)); UDP发送和接收结构体消息(最原始的做法)知道结构体的数据对齐的处理后,我们知道不能进行强转了,那么该怎么做呢? 我的做法是:将struct中的元素按字节大小一个个的存放到QByteArray中,QByteArray是连续的,接收时按大小再取出来就可以了。 直接上代码: 服务端(发送数据) //udpserver.h #include #include #include #include #include #define BYTE unsigned char struct Test_data{ int iNumber; char arrchResult[45]; char arrchCode[12]; bool bOutLimit_Flag; int iMark; BYTE byteResultType; }; class UdpServer : public QWidget { Q_OBJECT public: UdpServer(QWidget *parent = 0); public slots: void StartBtnClicked(); void timeout(); private: QPushButton *startBtn; QVBoxLayout *mainLayout; int port; bool isStarted; QUdpSocket *udpSocket; QTimer *timer; QByteArray m_byteArray; }; #endif // UDPSERVER_H //udepserver.cpp #include "udpserver.h" #include #include UdpServer::UdpServer(QWidget *parent) : QWidget(parent) { //初始化 Test_data data; data.iNumber=1; strcpy(data.arrchResult,"hello"); strcpy(data.arrchCode,"0x29"); data.bOutLimit_Flag=true; data.iMark=200; data.byteResultType=23; qDebug()setText(tr("stop")); timer->start(1000); isStarted=true; } else { startBtn->setText(tr("start")); isStarted=false; timer->stop(); } } void UdpServer::timeout() { udpSocket->writeDatagram(byteArray.data(),byteArray.size(),QHostAddress::Broadcast,port); }客户端接收数据 #ifndef UDPCLIENT_H #define UDPCLIENT_H #include #include #include #define BYTE unsigned char struct Test_data{ int iNumber; char arrchResult[45]; char arrchCode[12]; bool bOutLimit_Flag; int iMark; BYTE byteResultType; }; class UdpClient : public QWidget { Q_OBJECT public: UdpClient(QWidget *parent = 0); public slots: void dataReceived(); private: int port; QUdpSocket *udpSocket; }; #endif // UDPCLIENT_H #include "udpclient.h" #include #include #include UdpClient::UdpClient(QWidget *parent) : QWidget(parent) { setWindowTitle(tr("UDP Client")); port=5555; udpSocket=new QUdpSocket(this); connect(udpSocket,SIGNAL(readyRead()),this,SLOT(dataReceived())); bool result=udpSocket->bind(port); //绑定端口 if(!result) { QMessageBox::information(this,tr("error"),tr("udp socket create error")); return; } } void UdpClient::dataReceived() { while(udpSocket->hasPendingDatagrams()) //有未处理的报文 { Test_data* datagram=new Test_data; //用于存放接收的数据 QByteArray recvMsg; qDebug()pendingDatagramSize()); udpSocket->readDatagram(recvMsg.data(),recvMsg.size()); int pos=0; memcpy(&datagram->iNumber,recvMsg.constData(),sizeof(datagram->iNumber)); pos+=sizeof(datagram->iNumber); memcpy(datagram->arrchResult,recvMsg.constData()+pos,sizeof(datagram->arrchResult)); pos+=sizeof(datagram->arrchResult); memcpy(datagram->arrchCode,recvMsg.constData()+pos,sizeof(datagram->arrchCode)); pos+=sizeof(datagram->arrchCode); memcpy(&datagram->bOutLimit_Flag,recvMsg.constData()+pos,sizeof(datagram->bOutLimit_Flag)); pos+=sizeof(datagram->bOutLimit_Flag); memcpy(&datagram->iMark,recvMsg.constData()+pos,sizeof(datagram->iMark)); pos+=sizeof(datagram->iMark); memcpy(&datagram->byteResultType,recvMsg.constData()+pos,sizeof(datagram->byteResultType)); qDebug() |
CopyRight 2018-2019 实验室设备网 版权所有 |