• Qt+UDP及封装


    一、单播

    1、声明udp对象

    QUdpSocket* udpClient;

    2、new出对象

    udpClient = new QUdpSocket(this);

    3、分配本地地址(如果不分配,使用系统自动分配的),设置接收槽函数

    udpClient.bind("192.168.1.1”,8080);

    QObject::connect(this->udpClient,SIGNAL(readyRead()),this,SLOT(rcvData()));

    4、接收函数

    void Udp::rcvData()

    {

      if(this->udpClient->pendingDatagramSize() == 0)

        return;

      QByteArray ba;

      ba.resize(udpClient->pendingDatagramSize());

      QHostAddress tempHost("");

      quint16 port = 0;

      this->udpClient->readDatagram(ba.data(),udpClient->pendingDatagramSize(),&tempHost,&port);

    }

    5、发送

    void Udp::on_pushButton_3_clicked()

    {

      if(j == this->udpClient->writeDatagram(tempChar,j,ipAddress,port))

      {

        qDebuf()<<"发送成功"

      }

    }

    6、关闭

    udpClient.close();

    ps:1、udp套接字bind成功之后,状态是BoundState,close之后是UnconnectedState;

       2、bind是将一个ip和地址绑定,并使socket与这两个绑定在一起,通常是udp使用此函数;connectToHost是套接字连接至主机ip和端口,通常是tcp客户端连接至服务器使用此函数;

       3、每当udp的readyRead信号发出来后,一定要使用接收函数把数据接收了,否则下次来数据的时候不会发出此信号。

    二、组播

    组播:假设一个局域网内有多个计算机,每个计算机有一个IP,定义一个组播IP,把局域网中的某些计算机加入此组播IP,然后发送端向这个组播IP发送数据就完成了组播过程。

    三、广播

    向255:255:255:255发送

    ps:路由器会过滤多播(组播和广播)

    PS:开发流程

    四、封装

    头文件

    #ifndef MYUDP_H
    #define MYUDP_H
    
    #include <QObject>
    #include <QUdpSocket>
    
    class Myudp : public QObject
    {
        Q_OBJECT
    public:
        explicit Myudp(QObject *parent = nullptr);
        ~Myudp();
        void init(QString ip,uint port);
    
    private:
        QUdpSocket* udp;
    signals:
        void initSignal(QString ip,uint port);
        void quitSignal();
        void sendDataSignal(const QByteArray&);
    public slots:
        void initSlot(QString ip,uint port);
        void quitSlot();
        void rcvDataSlot();
        void sendUdpSlot(QString ip,uint port,QString info);
    };
    
    #endif // MYUDP_H

    源文件

    #include "myudp.h"
    #include "includes.h"
    #include "mymethod.h"
    
    /*****************************************************************/
    //作者:朱小勇
    //函数名称:构造函数
    //函数参数:NULL
    //函数返回值:NULL
    //函数作用:NULL
    //备注:NULL
    /*****************************************************************/
    Myudp::Myudp(QObject *parent) : QObject(parent)
    {
        emit quitSignal();
    }
    
    /*****************************************************************/
    //作者:朱小勇
    //函数名称:初始化
    //函数参数:NULL
    //函数返回值:NULL
    //函数作用:绑定udp端口
    //备注:NULL
    /*****************************************************************/
    void Myudp::init(QString ip,uint port)
    {
        QObject::connect(this,SIGNAL(initSignal(QString,uint)),this,SLOT(initSlot(QString,uint)));
        QObject::connect(this,SIGNAL(quitSignal()),this,SLOT(quitSlot()));
        emit initSignal(ip,port);
    }
    
    /*****************************************************************/
    //作者:朱小勇
    //函数名称:析构函数
    //函数参数:NULL
    //函数返回值:NULL
    //函数作用:NULL
    //备注:NULL
    /*****************************************************************/
    Myudp::~Myudp()
    {
    
    }
    
    /*****************************************************************/
    //作者:朱小勇
    //函数名称:初始化
    //函数参数:NULL
    //函数返回值:NULL
    //函数作用:NULL
    //备注:NULL
    /*****************************************************************/
    void Myudp::initSlot(QString ip,uint port)
    {
        if(nullptr!=udp)
        {
            udp->close();
            delete udp;
            udp = NULL;
        }
        Mymethod::record(QString("ready to bind udp port,%1:%2.").arg(ip).arg(port),PRINT_NORMAL);
        udp = new QUdpSocket();
        if(udp->bind(QHostAddress(ip),port))
        {
            Mymethod::record("bind success.",PRINT_NORMAL);
            QObject::connect(udp,SIGNAL(readyRead()),this,SLOT(rcvDataSlot()));
        }
        else
        {
            Mymethod::record("bind failed.",PRINT_ERR);
        }
    }
    
    /***********************************************/
    // 作者:朱小勇
    // 函数名称:回收内存槽函数,不能在析构函数里回收,因为析构函数也属于主线程
    // 函数作用:NULL
    // 函数参数:NULL
    // 函数返回值:NULL
    // 备注:NULL
    /***********************************************/
    void Myudp::quitSlot()
    {
        if(nullptr!=udp)
        {
            udp->close();
            delete udp;
            udp = NULL;
        }
        Mymethod::record("recycle udp resource",PRINT_INFO);
    }
    
    /*****************************************************************/
    //作者:朱小勇
    //函数名称:数据接收
    //函数参数:NULL
    //函数返回值:NULL
    //函数作用:NULL
    //备注:目前只接收SQL_CODE_开头的字符串,其他过滤
    /*****************************************************************/
    void Myudp::rcvDataSlot()
    {
        QByteArray ba;
        if(udp->hasPendingDatagrams())
        {
            ba.resize(udp->pendingDatagramSize());
            QHostAddress sender;
            quint16 senderPort;
            udp->readDatagram(ba.data(), ba.size(),&sender, &senderPort);
        }
        if(ba.size()!=VALUE_0)
        {
            emit sendDataSignal(ba);
        }
    }
    
    /*****************************************************************/
    //作者:朱小勇
    //函数名称:发送槽函数
    //函数参数:NULL
    //函数返回值:NULL
    //函数作用:NULL
    //备注:使用local8bit传输格式
    /*****************************************************************/
    void Myudp::sendUdpSlot(QString ip, uint port, QString info)
    {
        RET_IF_EAQU(nullptr,udp);
        if(VALUE__1 == udp->writeDatagram(info.toUtf8(),QHostAddress(ip),port))
        {
            Mymethod::record(getCodeLocate()+"udp send failed.",PRINT_ERR);
        }
    }

    PS:

    1、使用Qt的UDP绑定端口8000,往一个端口8001发送数据,如果这个8001端口没有被其他UDP建立,则本端口8000会收到一个“0.0.0.0”:55560的空字符串!!!!!我这里是55560,不知道都是这个端口还是随机的。

    这个问题让我查找了很久,一直不知道为啥8000接收打印,一直打印空字符串,后来关闭它的发送就没收到了,说明它发送一个非UDP端口则有这样一个反馈。

    不知道这个设计是UDP协议本身的,还是QT自作聪明设计的,感觉非常鸡肋,UDP本来就是不可靠传输,没必要告诉我发送成功与否,害我找了半天答案,真tm无语。

  • 相关阅读:
    checkbox全选
    table隔行变色与table单元格根据条件更改字体颜色
    document.ready和window.onload
    JS实现定时弹出广告
    CSS overflow属性与display属性
    OpenCV 安装步骤
    C#类的继承多态(虚方法,隐藏方法、抽象类和抽象方法)
    C#中虚方法,抽象方法和隐藏方法
    C#的重载与重写
    C#中可空类型
  • 原文地址:https://www.cnblogs.com/judes/p/6902949.html
Copyright © 2020-2023  润新知