草庐IT

QT下的UDP通信

饭了白a 2023-07-18 原文

QT中使用UDP通信

本例程已在单台机器和路由器下的多台机器上测试成功。
只支持文本发送,如果特殊的数据类型比如结构体、表格发送还得另定义编码与解析。
代码在文章末尾。点击跳转

发送端构建思路:

1、引入与UDP通信相关的库和功能;
2、头文件中声明通信相关的对象udpSocket和按键绑定函数等;
3、定义函数内容:
[3.1]按键绑定函数中为读取目标端口、目标IP与发送内容的功能;
[3.2]再用UdpSocket库的功能进行发送。

接收端构建思路:

[跳转到接收端]
1、引入与UDP通信相关的库和功能;
2、头文件中声明通信相关的对象udpSocket、按键绑定函数和接收处理函数等;
3、定义函数内容:
[3.1]读取端口号与IP地址,绑定端口,验证端口绑定成功;
[3.2]定义接收处理函数,与事件“接收到信号”进行绑定,每次接收到数据便执行此函数。

发送端

发送端的ui设计如下

其中,上方的PlainTextEdit组件是数据发送的输入框;下方的PlainTextEdit组件是信息输出框;
端口号输入框使用QSpinBox组件,IP输入框使用QLineEdit组件。
具体实现代码我会放在文末,[点击跳转]下面对关键部分代码做以下解释。

首先,UDP通信是QT安装时自带的,但是新建的QT工程并没有引入,需要在.pro工程文件中加入下面代码引入UDP通信功能:

QT += network

这样,在头文件中就可以包含与UDP通信相关的库了:

#include <QUdpSocket>

头文件内容如下:

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
    QUdpSocket *udpSocket;//
    QString getLocalIP();//获取本机IP地址
};

#endif // WIDGET_H

其中,有一个按键的绑定函数,一个QUdpSocket的指针对象,还有一个获取本机IP的函数。

构造函数如下,为udpSocket指针对象new一块空间:

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    QString localIP=getLocalIP();//本机IP
    this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);

    udpSocket=new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket
}

析构函数如下,断开udp通信以及手动删除new的对象:

Widget::~Widget()
{
    udpSocket->abort();
    delete udpSocket;
    delete ui;
}

按键绑定函数的定义如下,可以根据自身需要修改:

void Widget::on_pushButton_clicked()
{
    QString targetIP=ui->lineEdit->text();
    QHostAddress targetAddr(targetIP);  //目标IP

    quint16 targetPort = ui->spinBox->value();  //目标端口号
    QString msg = ui->plainTextEdit->toPlainText(); //发送内容
    QByteArray str = msg.toUtf8();

    udpSocket->writeDatagram(str, targetAddr, targetPort);  //发送函数

    ui->window->appendPlainText("[send]" + msg);   //信息栏显示

    ui->plainTextEdit->clear();
    ui->plainTextEdit->setFocus();
}

获取本机IP函数:

QString Widget::getLocalIP()
{
    QString hostName=QHostInfo::localHostName();//本地主机名
    QHostInfo   hostInfo=QHostInfo::fromName(hostName);
    QString   localIP="";

    QList<QHostAddress> addList=hostInfo.addresses();//

    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost=addList.at(i);
        if (QAbstractSocket::IPv4Protocol==aHost.protocol())
        {
            localIP=aHost.toString();
            break;
        }
    }
    return localIP;
}

接收端

接收端ui设计如下:

其中,目标端口使用的是QSpinBox组件,目标IP使用的是QLineEdit组件,接受框用PlainTextEdit组件。

同样在.pro文件中加入network模块

QT += network

头文件内容加入:

#include <QUdpSocket>

头文件内容如下

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
    QUdpSocket *udpSocket;//
    QString getLocalIP();//获取本机IP地址

private slots:
    void onSocketReadyRead();//读取socket传入的数据
    void on_pushButton_clicked();
};
#endif // WIDGET_H

与发送端的构成类似,信号函数多了一个读取socket传入的数据函数:void onSocketReadyRead()

各个函数的定义如下:

构造函数如下

由于接收端需要适时监听端口号收到的信息,因此需要将readyRead()信号与自定义的信号读取函数onSocketReadyRead()关联。

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    QString localIP=getLocalIP();//本机IP
    this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);

    udpSocket=new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket
    connect(udpSocket,SIGNAL(readyRead()),
            this,SLOT(onSocketReadyRead()));
//    udpSocket=new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket
//    connect(udpSocket,SIGNAL(readyRead()),
//            this,SLOT(onSocketReadyRead()));
}

析构函数如下

Widget::~Widget()
{
    udpSocket->abort();
    delete udpSocket;
    delete ui;
}

要监听端口来接受信息,首先要对端口号进行绑定,当udpSocket->bind(port)返回true时表示端口绑定成功

void Widget::on_pushButton_clicked()
{
    quint16 port = ui->spinBox->value(); //本机UDP端口
    if (udpSocket->bind(port)) //绑定端口成功
    {
        ui->plainTextEdit->appendPlainText("**成功绑定端口");
        ui->plainTextEdit->appendPlainText("**绑定端口:" +
                QString::number(udpSocket->localPort()));    }
}

socket读取函数如下,当端口监听到有数据发来,就会执行此函数

void Widget::onSocketReadyRead()
{
    while(udpSocket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());  //数据格式统一

        QHostAddress peerAddr;
        quint16 peerPort;
        udpSocket->readDatagram(datagram.data(),
                                datagram.size(),&peerAddr,&peerPort);   //接收数据
        QString str=datagram.data();    //数据转换为QT的ui界面使用的QString类型

        QString peer="[From "+peerAddr.toString()+":"
                +QString::number(peerPort)+"] ";

        ui->plainTextEdit->appendPlainText(peer+str);
    }
}

获取ip函数与发送端相同

QString Widget::getLocalIP()
{
    QString hostName=QHostInfo::localHostName();//本地主机名
    QHostInfo   hostInfo=QHostInfo::fromName(hostName);
    QString   localIP="";

    QList<QHostAddress> addList=hostInfo.addresses();//

    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost=addList.at(i);
        if (QAbstractSocket::IPv4Protocol==aHost.protocol())
        {
            localIP=aHost.toString();
            break;
        }
    }
    return localIP;
}

演示

IP查询可以cmd到终端输入ipconfig查询。
端口号绑定不成功的话换一个数字重试,可能与计算机已经占用的端口发生了冲突,一般选择时尽量选择大一些的端口号避免冲突。
不要开串口调试工具同时进行调试,使用时应该断开串口调试共苦,原因就是上一点的串口冲突问题。
单机测试使用时,开两个QT应用,发送和接收程序都运行,先根据自己电脑的IP地址设置号IP,端口号保持一致。在接收端点击绑定端口,端口绑定成功后会有提示,再到发送端发送自己像发送的内容,图片中发送的Hello已经成功接收到。
多机使用时,保证IP处于同一网段,接收端和发送端端口设置一致,IP使用接收端电脑的IP地址。

代码地址:

❤️跳转过来啦❤️

百度云

链接:https://pan.baidu.com/s/1VrwGKHWd2RRv_PNu7tUZvg
提取码:pkci

Github

https://github.com/FLBa9762/Qt-UdpSocket-Code.git

有关QT下的UDP通信的更多相关文章

  1. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  2. Qt Designer的简单使用 - 2

    在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q

  3. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  4. 关于Qt程序打包后运行库依赖的常见问题分析及解决方法 - 2

    目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'

  5. ruby-on-rails - Rails 是否支持监听 UDP 套接字的简洁方式? - 2

    在Rails中,什么是集成更新模型某些元素的UDP监听过程的最佳方式(特别是它将向其中一个表添加行)。简单的答案似乎是在同一个进程中使用UDP套接字对象启动一个线程,但我什至不清楚我应该在哪里做适合Rails方式的事情。有没有一种巧妙的方法来开始收听UDP?具体来说,我希望能够编写一个UDPController并在每个数据报消息上调用一个特定的方法。理想情况下,我希望避免在UDP上使用HTTP(因为它会浪费一些在这种情况下非常宝贵的空间),但我完全控制消息格式,因此我可以为Rails提供它需要的任何信息。 最佳答案 Rails是一个

  6. 1个串口用1根线实现多机半双工通信+开机控制电路 - 2

    功能需求:主机使用一个串口,与两个从机进行双向通信,主机向从机发送数据,从机能够返回数据,由于结构限制,主机与从机之间只有3根线(电源、地、数据线),并且从机上没有设物理的电源开关,需要通过与主机连接的数据线来控制开机,总结如下:1、数据线只有1根2、能够双向通信3、主机能够控制从机开机4、主机可以单独向1个从机发数据,也可以同时向两个从机发送数据根据需求,设计出如下电路:工作原理分析:VCC_24V_IN、GND、LINE_L(LINE_R)三根线接线连接到从机,电源开启电路是从机内部的电源控制。开机的逻辑:*主机先上电,LINE_L因为主机的R1上拉而有高电平,使Q6导通,Q5的G极电压被

  7. ruby - 如何创建与帧缓冲区通信的 Ruby 应用程序? - 2

    我有一个RaspberryPiTFT7"触摸屏显示器,我想创建一个简单的应用程序来显示和输出系统数据(即CPU使用率、温度等)。我注意到目前常见的实现方法是使用pygame库输出到显示器连接到的帧缓冲区/dev/fb1。我想执行相同的操作,但使用Ruby,因为我更熟悉这门语言。有人可以为我指明正确的方向,让我知道如何开始吗?我查看了ruby​​game和gosu库,它们似乎能够做我想做的事情,即绘制屏幕,​​但我找不到任何关于如何将输出定向到的信息帧缓冲区本身。 最佳答案 rubycorelib有一个IO您应该能够使用该类将输出定向

  8. jquery - 根据按下的链接显示特定类别 | Rails 上的 Ruby - 2

    我有一个博客,它在同一页面上呈现每个类别及其各自的子类别。(索引View)我有一个导航部分,我想利用它根据按下的链接仅呈现特定子类别的帖子。我不知道单独使用ruby​​是否可行,所以我认为JQuery可能是这种方式。blog_categoriesindex.html.erb:NEWSAllNewsGoodNewsBadNewsREVIEWSAllReviewsSoftwareHardware...blog_categories_controller:defindex@category=BlogCategory.find_by_id(params[:id])unless@category

  9. [蓝桥杯单片机]学习笔记——串口通信的基本原理与应用 - 2

    目录一、原理部分1、什么是串行通信(1)并行通信与串行通信(2)串行通信的制式(3)串行通信的主要方式  2、配置串口(1)SCON和PCON:串行口1的控制寄存器(2)SBUF:串行口数据缓冲寄存器 (3)AUXR:辅助寄存器​编辑(4)ES、PS:与串行口1中断相关的寄存器(5)波特率设置  3、串口框架编写二、程序案例一、原理部分1、什么是串行通信(1)并行通信与串行通信微控制器与外部设备的数据通信,根据连线结构和传送方式的不同,可以分为两种:并行通信和串行通信。并行通信:数据的各位同时发送与接收,每个数据位使用一条导线,这种方式传输快,但是需要多条导线进行信号传输。串行通信:数据一位一

  10. ruby-on-rails - Rails 开发模式下的日志轮换? - 2

    对于Rails3.1(很快将是3.2),我有非常详细的日志,其中包含大量额外的工作人员信息。我通常会得到数GB的development.log文件。我看到过一些关于轮换生产日志的讨论,但是我没有发现任何似乎适用于development.log轮换的内容。您如何在每100.megabytes左右轮换您的development.log?或者我更喜欢实际截断文件头,以便只有最近的项目保留在日志中,最近的条目最多100MB。我已经玩了一点,并且越来越多地认为目前不存在这样的东西,也许我应该实现一些将以某种方式使用ruby​​File.truncate的东西,但是我到目前为止,我还不确定它在文件

随机推荐