Qt realizes udp unicast, udp multicast, and sends and receives messages

Qt implements udp to send and receive messages, determine the validity, and parse the message data. If communication fails during debugging, try to close the firewall and close other unrelated network cards, especially virtual machine network cards.
UdpCenter.h

#ifndef UDPCENTER_H
#define UDPCENTER_H

#include <QObject>
#include <QUdpSocket>
#include <QHostAddress>
/**
 * @brief UDP通信报文固定报文头
 */
struct CMMI_CommonHeader{
    
    
    unsigned char flag; //标识
    unsigned short length;//大小
    unsigned char serialNum;//序号
    unsigned int time;//时间戳
};
class UdpCenter : public QObject
{
    
    
    Q_OBJECT
public:
    explicit UdpCenter(QObject *parent = 0);
    void sendData(QByteArray data,QString ip);
    void initSocket();//初始化UDP
    void stopSocket();//断开UDP
public slots:
    void readPendingDatagrams();
private:
    void processTheDatagram(QByteArray recvBuff);

private:
    QUdpSocket *m_pUdpSocketRece;           //接收数据
    QUdpSocket *m_pUdpSocketSend;           //发送数据
};

#endif // UDPCENTER_H

UdpCenter.cpp

#include "udpcenter.h"
#include "rgglogal.h"
#include "protocol/protocol.h"

using namespace PROTOCOL;

UdpCenter::UdpCenter(QObject *parent) : QObject(parent)
{
    
    
    m_pUdpSocketRece = nullptr;
    m_pUdpSocketSend = nullptr;
}

/**
 * @brief 发送报文
 * @param QByteArray报文数据
 */
void UdpCenter::sendData(QByteArray data,QString ip)
{
    
    
    if(m_pUdpSocketSend)
    {
    
    
        m_pUdpSocketSend->writeDatagram(data,QHostAddress(ip),21505);
    }
}

/**
 * @brief 初始化UDP套接字,本例中接收和发送分别定义了一个套接字
 */
void UdpCenter::initSocket()
{
    
    
    //接收数据套接字
    m_pUdpSocketRece = new QUdpSocket(this);
    bool isOKm_pUdpSocketRece = m_pUdpSocketRece->bind(QHostAddress::AnyIPv4,21505);

    qDebug()<<"["<<__FILE__<<"]"<<__LINE__<<__FUNCTION__<<"isOKm_pUdpSocketRece "<<isOKm_pUdpSocketRece;
    m_pUdpSocketRece->joinMulticastGroup(QHostAddress("224.0.100.1"));//加入组播

    //发送数据套接字
    m_pUdpSocketSend = new QUdpSocket(this);
    bool isOKm_pUdpSocketSend = m_pUdpSocketSend->bind(QHostAddress::AnyIPv4,21504,QUdpSocket::ShareAddress);
    qDebug()<<"["<<__FILE__<<"]"<<__LINE__<<__FUNCTION__<<"isOKm_pUdpSocketSend "<<isOKm_pUdpSocketSend;

    connect(m_pUdpSocketRece, SIGNAL(readyRead()),this, SLOT(readPendingDatagrams()));
}

/**
 * @brief 断开UDP
 */
void UdpCenter::stopSocket()
{
    
    
    m_pUdpSocketRece->disconnectFromHost();
    m_pUdpSocketRece->close();
    //m_pUdpSocketRece->abort();
    m_pUdpSocketSend->disconnectFromHost();
    m_pUdpSocketSend->close();
    //m_pUdpSocketSend->abort();
    m_pUdpSocketRece = nullptr;
    m_pUdpSocketSend = nullptr;
}

/**
 * @brief 对接收的网络数据进行有效性判断
 */
void UdpCenter::readPendingDatagrams()
{
    
    
    QByteArray datagram;
    while (m_pUdpSocketRece->hasPendingDatagrams()) {
    
    

        datagram.resize(m_pUdpSocketRece->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;

        m_pUdpSocketRece->readDatagram(datagram.data(), datagram.size(),&sender, &senderPort);
        qDebug()<<"["<<__FILE__<<"]"<<__LINE__<<__FUNCTION__<<"recedatagram.size() "<<datagram.size();
        processTheDatagram(datagram);
    }
}

/**
 * @brief 对接收的网络数据进行业务判断,处理数据
 * @param recvBuff 网络数据
 */
void UdpCenter::processTheDatagram(QByteArray recvBuff)
{
    
    
    if(recvBuff.size()<sizeof(CMMI_CommonHeader))
    {
    
    
        return ;
    }

	//解析报文头部
    CMMI_CommonHeader t_tenpHead;
    memset((char*)&t_tenpHead, 0,sizeof(CMMI_CommonHeader));
    memcpy((char*)&t_tenpHead, recvBuff.data(), sizeof(CMMI_CommonHeader));

	//根据报文头判断报文类型
    switch(t_tenpHead.flag)
    {
    
    
    case FLAG_SAR_Heart://设备心跳报文
    {
    
    
        CMMI_Device_Heart *t_SARHeart = (CMMI_Device_Heart*)(recvBuff.data() + sizeof(CMMI_CommonHeader));//去掉头部,取后面120位

        CGlogal::instance()->recvHeart(t_SARHeart);//后续处理报文
    }break;
    case FLAG_SAR_TgtInfo://目标信息报文
    {
    
    
        CMMI_Device_TgtInfo *t_Device_TgtInfo = {
    
    0};
        t_Device_TgtInfo = (CMMI_Device_TgtInfo*)(recvBuff.data()+sizeof(CMMI_CommonHeader));
        CGlogal::instance()->recvDeviceTgtInfo(t_Device_TgtInfo);//后续处理报文
    }break;
    case FLAG_SAR_TgtInfo_Tend://目标库上报报文
    {
    
    
        CMMI_Tgtlib_Upload *t_Tgtlib_Upload = (CMMI_Tgtlib_Upload*)(recvBuff.data()+sizeof(CMMI_CommonHeader));
        CGlogal::instance()->receTgtLibUpload(t_Tgtlib_Upload);//后续处理报文
    }break;
    }
}

Send message call example

/**
 * @param t_ip,目标IP
 * @param t_array,数据,不包含头
 * @param t_flag,报文标识
 */
void MainWindow::slotSendDisturbCtrl(QString t_ip, QByteArray t_array)
{
    
    
    static unsigned int static_DisturbCtrlSerialNum = 0;//报文序号,递增
    if(static_DisturbCtrlSerialNum == 256)
        static_DisturbCtrlSerialNum = 0;
    PROTOCOL::CMMI_CommonHeader t_Device_ParamSetHeader;//报文头
    memset(&t_Device_ParamSetHeader,0,sizeof(PROTOCOL::CMMI_CommonHeader));//报文头初始化为0
    t_Device_ParamSetHeader.flag = PROTOCOL::FLAG_Center_SARTgtCtrl;
    t_Device_ParamSetHeader.time = this->getCurrTime();
    t_Device_ParamSetHeader.serialNum = static_DisturbCtrlSerialNum++;
    t_Device_ParamSetHeader.length = 8+t_array.size();
    //发送报文,先添加报文头,再添加报文正文
    QByteArray t_DisturbCtrlText;
    t_DisturbCtrlText.append((char*)&t_Device_ParamSetHeader,8);
    t_DisturbCtrlText.append(t_array);
    m_myUDP->sendData(t_DisturbCtrlText,t_ip);//IP可以是组播地址,以广播形式发送,4个255代表发送给所有组播地址
    
    //如果传进来的报文正文是结构体,需要转换为QByteArray:t_Tgtlib_Bind为结构体
    //QByteArray t_array = QByteArray((char*)&t_Tgtlib_Bind,sizeof(PROTOCOL::CMMI_Tgtlib_Bind));
}

Guess you like

Origin blog.csdn.net/weixin_40355471/article/details/110746609