Qt实现udp单播、udp组播,发送和接收报文

Qt实现udp发送和接收报文,有效性判断,解析报文数据,调试中如遇到通信失败,尝试关闭防火墙、关闭其他无关网卡,尤其是虚拟机网卡。
UdpCenter.h

#ifndef UDPCENTER_H
#define UDPCENTER_H

#include 
#include 
#include 
/**
 * @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;
    }
}

发送报文调用示例

/**
 * @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));
}

你可能感兴趣的:(QT,c++)