• QT和网络调试助手之间的UDP通信


    一、背景

    之前一篇博客实现了两个网络调试助手之间的UDP通信。

    文章链接:在MacOS上实现两个网络调试助手的UDP通信测试

    通过上面我们大致知道了UDP通信的一些过程,在本篇博客中,我们更进一步,实现QT程序和网络调试助手之间的通信。

    二、实现过程

    可以参考这两篇博客:

    Qt 网络编程-UDP

    QT:UDP网络编程实现

    简述

    UDP(User Data Protocol),用户数据报协议,是一种简单轻量级、不可靠、面向数据报、无连接的传输层协议,可以应用在可靠性不是十分重要的场合,如短消息、广播信息等。

    适用于以下几种情况:

    A . 网络数据大多为短消息。

    B . 拥有大量客户端

    C . 对数据安全性无特殊要求

    D . 网络负担非常重,但对响应速度要求高。

    同样,如果要在Qt 进行网络编程首先需要在 .pro文件添加: QT += network。Qt 中通过 QUdpSocket类实现UDP 协议的编程。
    本文介绍一个基于 UDP 协议的广播应用 ,它由UDP 服务器和 UDP 客户端两部分组成。

    其实,UDP没有特定的server端 和 client,简单来说就是向特定的ip发送报文,所以,也可以分为发送端和接收端。

    QUdpSocket类允许发送和接收 UDP 数据报,继承自QAbstractSocket 。QUdpSocket 支持IPv4 广播。QUdpSocket 还支持多播。

    UDP协议工作原理及编程模型

    1 > UDP 协议工作原理

    UDP 客户端向 UDP 服务器发送一定长度的请求报文,报文大小的限制与各系统的协议实现有关,但不得超过其下层 IP 协议规定的64KB;UDP服务器同样以报文形式作出响应。如果服务器未收到此请求,客户端不会进行重发,因此报文的传输是不可靠的。

    img

    例如,常用的聊天工具------腾讯QQ软件就是使用UDP协议发送信息的,因此有时会出现收不到信息的情况。

    2 > UDP 编程模型

    基于UDP 协议的经典编程模型,程序编写的通用流程如下:

    img

    由上图可知,在 UDP 方式下,客户端并不与服务器建立连接,它只负责调用发送函数向服务器发出数据报。同样,服务器也不与客户端接收连接,只负责调用接收函数,等待来自某客户端的数据到达。

    UDP 接收端

    Qt 的 UdpSocket 接收消息原则:

    A . new一个UdpSocket

    B . 调用UdpSocket的bind方法,同时指定端口号

    C . 使用 connect 将接收消息函数和UdpSocket对象做关联

    D . 在接受消息槽函数当中调用 readDatagram 接收消息

    udpclient.h

    #ifndef UDPCLIENT_H
    #define UDPCLIENT_H
     
    #include 
    #include 
    #include 
    #include 
    #include 
     
    class UdpClient : public QDialog
    {
        Q_OBJECT
        
    public:
        UdpClient(QWidget *parent = 0,Qt::WindowFlags f=0);
        ~UdpClient();    
    public slots:
        void CloseBtnClicked();
        void dataReceived();
    private:
        QTextEdit *ReceiveTextEdit;
        QPushButton *CloseBtn;
        QVBoxLayout *mainLayout;
        int port;
        QUdpSocket *udpSocket;
    };
     
    #endif // UDPCLIENT_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    udpclient.cpp

    #include "udpclient.h"
    #include 
    #include 
     
    UdpClient::UdpClient(QWidget *parent,Qt::WindowFlags f)
        : QDialog(parent,f)
    {
        setWindowTitle(tr("UDP Client")); //设置窗体的标题
        //初始化各个控件
        ReceiveTextEdit = new QTextEdit(this);
        CloseBtn = new QPushButton(tr("Close"),this);
        //设置布局
        mainLayout=new QVBoxLayout(this);
        mainLayout->addWidget(ReceiveTextEdit);
        mainLayout->addWidget(CloseBtn);
        connect(CloseBtn,SIGNAL(clicked()),this,SLOT(CloseBtnClicked()));
     
        port =5555;//设置UDP的端口号参数,指定在此端口上监听数据
        udpSocket = new QUdpSocket(this); //创建一个UdpSocket
        //连接QIODevice的readyRead()信号,readyRead()表示有消息到来这个信号,
        connect(udpSocket,SIGNAL(readyRead()),this,SLOT(dataReceived()));
        //指定绑定端口号,接收消息必须绑定端口号,发送消息则不需要绑定
        bool result=udpSocket->bind(port);//绑定到指定的端口上
        //取消绑定端口号使用:udpsocket->close()方法
        if(!result)
        {
            QMessageBox::information(this,tr("error"),tr("udp socket create error!"));
            return;
        }
    }
     
    UdpClient::~UdpClient()
    {
        
    }
     
    void UdpClient::CloseBtnClicked()
    {
        close();
    }
     
    void UdpClient::dataReceived()
    {
        //判断UdpSocket中是否有数据可读
        while(udpSocket->hasPendingDatagrams())
        {
            //实现读取数据报
            QByteArray datagram;
            datagram.resize(udpSocket->pendingDatagramSize());
            udpSocket->readDatagram(datagram.data(),datagram.size());
     
            QString msg=datagram.data();
            ReceiveTextEdit->insertPlainText(msg);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    UDP 发送端

    Qt 的 UdpSocket 发送消息:

    A . new 一个 UdpSocket

    B . 调用 writeDatagram 发送消息

    udpserver.h

    #ifndef UDPSERVER_H
    #define UDPSERVER_H
     
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
     
    class UdpServer : public QDialog
    {
        Q_OBJECT
        
    public:
        UdpServer(QWidget *parent = 0,Qt::WindowFlags f=0);
        ~UdpServer();
    public slots:
        void StartBtnClicked();
        void timeout();
    private:
        QLabel *TimerLabel;
        QLineEdit *TextLineEdit;
        QPushButton *StartBtn;
        QVBoxLayout *mainLayout;
        int port;
        bool isStarted;
        QUdpSocket *udpSocket;
        QTimer *timer;
    };
     
    #endif // UDPSERVER_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    udpserver.cpp

    #include "udpserver.h"
    #include 
     
    UdpServer::UdpServer(QWidget *parent, Qt::WindowFlags f)
        : QDialog(parent,f)
    {
        setWindowTitle(tr("UDP Server"));  //设置窗体的标题
        //初始化各个控件
        TimerLabel = new QLabel(tr("计时器:"),this);
        TextLineEdit = new QLineEdit(this);
        StartBtn = new QPushButton(tr("开始"),this);
        //设置布局
        mainLayout = new QVBoxLayout(this);
        mainLayout->addWidget(TimerLabel);
        mainLayout->addWidget(TextLineEdit);
        mainLayout->addWidget(StartBtn);
        connect(StartBtn,SIGNAL(clicked()),this,SLOT(StartBtnClicked()));
     
        port =5555; //设置UDP的端口号参数,服务器定时向此端口发送广播信息
        isStarted=false;
        udpSocket = new QUdpSocket(this); //创建一个UdpSocket
        //定时发送广播信息
        timer = new QTimer(this);
        connect(timer,SIGNAL(timeout()),this,SLOT(timeout()));
    }
     
    UdpServer::~UdpServer()
    {
        
    }
     
    void UdpServer::StartBtnClicked()
    {
        if(!isStarted)
        {
            StartBtn->setText(tr("停止"));
            timer->start(1000);
            isStarted =true;
        }
        else
        {
            StartBtn->setText(tr("开始"));
            isStarted = false;
            timer->stop();
        }
    }
     
    //timeout()函数完成了向端口发送广播信息的功能
    void UdpServer::timeout()
    {
        QString msg = TextLineEdit->text();
        int length=0;
        if(msg=="")
        {
           return;
        }
        //QHostAddress::Broadcast 指定向广播地址发送,可以改成固定IP,则表示向特定IP发送
        if((length=udpSocket->writeDatagram(msg.toLatin1(),msg.length(),QHostAddress::Broadcast,port))!=msg.length())
        {
            return;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    运行UDP接收端和发送端

    img

    运行UDP发送端发送数据给网络调试助手

    注意端口号的设置

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xOAAJCE4-1669726603097)(/Users/apple/Library/Application Support/typora-user-images/image-20221129205554562.png)]

  • 相关阅读:
    CSB ---> (XXE)XML基础
    @Embeddable and @ElementCollection 嵌套导致SpringBoot程序无法启动的问题
    什么是nacos/cas/fastdfs
    HTML(23)——垂直对齐方式
    JavaScript中作用域问题讨论及示例代码探究
    JSP教师辅助办公软件教学进程管理系统yeclipse开发mysql数据库bs框架java编程jdbc详细设计
    一文带你了解【深度学习】中CNN、RNN、LSTM、DBN等神经网络(图文解释 包括各种激活函数)
    卷积神经网络(CNN)
    大模型日报|20 篇必读的大模型论文
    力扣-383.赎金信
  • 原文地址:https://blog.csdn.net/qq_41854911/article/details/128105144