Qt收发tcp/udp报文,报文解析

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,后面的数据是发送端未赋值的乱码,不用处理。

ASCII码表

  • 6
    点赞
  • 73
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值