赞
踩
Qt中udp和tcp收发方式略有不同。
//定义报文结构体 //通用报文头格式,所有报文均包含该头部 struct VTM_CommonHeader{ unsigned int uType; //业务类型 unsigned int uSize;//报文大小 }; struct VTM_MSCALL_REQUEST{ VTM_CommonHeader head; unsigned int userNumber;//用户号 char ip[32];//营业员ip地址 VTM_MSCALL_REQUEST() { memset(this,0,sizeof(VTM_MSCALL_REQUEST)); } }; //组包 QString ip = "127.0.0.1"; DATASTRUCT::VTM_MSCALL_REQUEST tVTM_CALL_REQUEST; tVTM_CALL_REQUEST.head.uType = 1001; tVTM_CALL_REQUEST.head.uSize = sizeof (DATASTRUCT::VTM_MSCALL_REQUEST); tVTM_CALL_REQUEST.userNumber = 10086; memcpy(tVTM_CALL_REQUEST.ip,ip.toLatin1().data(),sizeof(tVTM_CALL_REQUEST.ip)); //tcp发送 QTcpSocket *m_pTcpSocket; m_pTcpSocket = new QTcpSocket(this); m_pTcpSocket->connectToHost(QHostAddress("127.0.0.1"),9000); m_pTcpSocket->waitForConnected(3000); m_pTcpSocket->write(QByteArray((char*)&tVTM_CALL_REQUEST,sizeof (DATASTRUCT::VTM_MSCALL_REQUEST)));//发送数据 m_pTcpSocket->waitForBytesWritten(); //udp发送 QUdpSocket *pSendUdp; QString mdfIP = "127.0.0.1";//对端IP pSendUdp = new QUdpSocket(this); pSendUdp->writeDatagram(QByteArray((char*)&tVTM_CALL_REQUEST,sizeof (DATASTRUCT::VTM_MSCALL_REQUEST)),QHostAddress(mdfIP),9000); pSendUdp->waitForBytesWritten();
QUdpSocket不能使用readAll,否则会报错QIODevice::read (QUdpSocket): device not open;
通过readyRead信号触发槽函数读取数据。
//tcp接收
QTcpSocket *m_pTcpSocket;
m_pTcpSocket = new QTcpSocket(this);
//如果是tcp客户端要connectToHost,如果是tcp服务端则要赋值与QTcpServer连接的QTcpSocket
QByteArray array = m_pTcpSocket->readAll();
//udp接收
QUdpSocket *pRevUdp;
pRevUdp = new QUdpSocket(this);
pRevUdp->bind(QHostAddress::Any,9000);
while (pRevUdp->hasPendingDatagrams())
{
QByteArray mBuffer;
qint64 len = pRevUdp->pendingDatagramSize();
QHostAddress sender;
quint16 senderPort;
qint64 succLen = pRevUdp->readDatagram(mBuffer.data(),len,&sender, &senderPort);
}
对接收到数据QByteArray转换为结构体变量
DATASTRUCT::VTM_MSCALL_REQUEST tVTM_MSCALL_REQUEST;
memset(&tVTM_MSCALL_REQUEST,0,sizeof (DATASTRUCT::VTM_MSCALL_REQUEST));
memcpy(&tVTM_MSCALL_REQUEST,array.data(),sizeof (DATASTRUCT::VTM_MSCALL_REQUEST));
报文16进制字串每两位加空格
QString Instance::HexToHuman(QString str) { QString strAfter; int flag=0; for(int index=0;index<str.size();index++) { strAfter.append(str.at(index)); flag++; if(flag == 2) { flag=0; strAfter.append(" "); } } return strAfter; }
有时我们会把报文写入日志或打印出来,下面介绍如何解析打印出来的原始报文:
QByteArray array
qDebug()<< array.toHex()
上面的报文结构体VTM_MSCALL_REQUEST长度是44个字节,打印出来的是16进制字串,每两位代表一个16进制字符,因此打印出来是88位,比如:
e90300002c000000662700003132372e302e302e31000000ff000000a1bf55da008100807056a70200000000
报文开头是unsigned int uType,4个字节,占8位,也就是e9030000,每两位代表1个字节,这里注意报文默认是高字节在前,低字节在后,转换后是000003e9,转换位十进制就是1001;
紧接着后面8位是2c000000,转换后是0000002c,转换十进制是44,unsigned int uSize;//报文大小;
再后面8位是66270000,转换后是00002766,转换十进制是10086,是unsigned int userNumber;//用户号;
最后64位是char ip[32],对应32个字节,这里char是字符类型,需要对照ASCII码表转换,最后64位:3132372e302e302e31000000ff000000a1bf55da008100807056a70200000000;
第一个字节31是16进制,转换位十进制是49,ASCII码表查询49代表1,以此类推31 32 37 2e 30 2e 30 2e 31,代表127.0.0.1,后面的数据是发送端未赋值的乱码,不用处理。

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。