【Qt开发流程】之UDP

news/2024/5/18 14:09:01 标签: qt, udp, 单片机

概述

UDP (User Datagram Protocol)是一种简单的传输层协议。与TCP不同,UDP不提供可靠的数据传输和错误检测机制。UDP主要用于那些对实时性要求较高、对数据传输可靠性要求较低的应用,如音频、视频、实时游戏等。

UDP使用无连接的数据报传输模式。在传输数据之前,发送方和接收方不需要建立一个持久的连接,只需发送数据报文即可。每个数据报文都是独立的,没有前后关系,因此也不必保证按照发送的顺序接收。

UDP协议的特点包括:

  1. 无连接性:发送方和接收方之间不需要建立和维护连接。
  2. 快速性:由于无连接性,UDP的传输速度相对较快。
  3. 无可靠性保证:UDP不提供可靠的数据传输,不保证数据的完整性和正确性。
  4. 简单性:UDP的协议头部较短,占用的数据传输量较小。

UDP数据传输示意图:
在这里插入图片描述

QUdpSocket

QUdpSocket类提供了UDP套接字。
QUdpSocket是QAbstractSocket的一个子类,它允许发送和接收UDP数据报。
这里的socket就是所谓的套接字,简单地说,就是一个Ip地址+一个Port端口号。
使用这个类最常见的方法是使用bind()绑定到一个地址和端口,然后调用writeDatagram()readDatagram() / receiveDatagram()来传输数据。如果想使用标准的QIODevice函数read(), readLine(), write()等,必须首先通过调用connectToHost()将套接字直接连接到对等体。
套接字每次将数据报写入网络时都会发出bytesWritten()信号。如果您只想发送数据报,则不需要调用bind()
每当数据报到达时,就会发出readyRead()信号。在这种情况下,hasPendingDatagrams()返回true。调用pendingDatagramSize()来获取第一个挂起数据报的大小,并调用readDatagram()receiveDatagram()来读取它。
注意:当接收readyRead()信号时,应该读取传入的数据报,否则将不会为下一个数据报发出该信号。

QUdpSocket支持IPv4广播,IPv4广播是一种在IPv4网络中向同一网络中的所有主机发送数据的方式。
在IPv4网络中,广播地址是一个特殊的IP地址,用于指示对应网络中的所有主机。

IPv4广播使用的是一个特定的IP地址,即网络地址的所有主机位都为1的情况下,主机地址为0。例如,在一个192.168.0.0/24的网络中,广播地址为192.168.0.255。

使用IPv4广播,可以将数据一次性发送到同一网络中的所有主机,而不需要逐个发送给每个主机。这在某些应用中非常有用,例如在局域网中通知所有主机进行某项操作,或者在DHCP协议中分发IP地址等。

然而,由于IPv4广播发送的数据会被同一网络中的所有主机接收,这也可能会造成一些安全和性能问题。因此,在IPv4网络中广播的使用需要谨慎,并需要对广播进行适当的限制和控制。

例如:

  void Server::initSocket()
  {
      udpSocket = new QUdpSocket(this);
      udpSocket->bind(QHostAddress::LocalHost, 7755);

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

  void Server::readPendingDatagrams()
  {
      while (udpSocket->hasPendingDatagrams()) {
          QNetworkDatagram datagram = udpSocket->receiveDatagram();
          processTheDatagram(datagram);
      }
  }

QUdpSocket还支持UDP组播。使用joinMulticastGroup()leaveMulticastGroup()来控制组成员,使用QAbstractSocket::MulticastTtlOptionQAbstractSocket::MulticastLoopbackOption来设置TTLloopback套接字选项。使用setMulticastInterface()控制组播数据报的出接口,使用multicastInterface()进行查询。
使用QUdpSocket,还可以使用connectToHost()与UDP服务器建立虚拟连接,然后使用read()和write()交换数据报,而无需指定每个数据报的接收者。

示例

以下是一个发送者,一个接收者,发送者定时发送数据,接收者进行显示
sender.h

#include <QWidget>

QT_BEGIN_NAMESPACE
class QDialogButtonBox;
class QLabel;
class QPushButton;
class QTimer;
class QUdpSocket;
QT_END_NAMESPACE

class Sender : public QWidget
{
    Q_OBJECT

public:
    Sender(QWidget *parent = 0);

private slots:
    void startBroadcasting();
    void broadcastDatagram();

private:
    QLabel *statusLabel;
    QPushButton *startButton;
    QPushButton *quitButton;
    QDialogButtonBox *buttonBox;
    QUdpSocket *udpSocket;
    QTimer *timer;
    int messageNo;
};

sender.cpp

#include <QtWidgets>
#include <QtNetwork>

#include "sender.h"

Sender::Sender(QWidget *parent)
    : QWidget(parent)
{
    statusLabel = new QLabel(tr("绑定 端口 45454"));
    statusLabel->setWordWrap(true);

    startButton = new QPushButton(tr("&Start"));
    quitButton = new QPushButton(tr("&Quit"));

    buttonBox = new QDialogButtonBox;
    buttonBox->addButton(startButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);

    timer = new QTimer(this);

    udpSocket = new QUdpSocket(this);

    messageNo = 1;

    connect(startButton, SIGNAL(clicked()), this, SLOT(startBroadcasting()));
    connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
    connect(timer, SIGNAL(timeout()), this, SLOT(broadcastDatagram()));

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(statusLabel);
    mainLayout->addWidget(buttonBox);
    setLayout(mainLayout);

    setWindowTitle(tr("广播发送"));
}

void Sender::startBroadcasting()
{
    startButton->setEnabled(false);
    timer->start(1000);
}

void Sender::broadcastDatagram()
{
    statusLabel->setText(tr("现在 广播 信息 %1").arg(messageNo));

    QByteArray datagram = "广播 信息 " + QByteArray::number(messageNo);
    udpSocket->writeDatagram(datagram.data(), datagram.size(),
                             QHostAddress::Broadcast, 45454);

    ++messageNo;
}

receiver.h

#include <QWidget>

QT_BEGIN_NAMESPACE
class QLabel;
class QPushButton;
class QUdpSocket;
class QAction;
QT_END_NAMESPACE

class Receiver : public QWidget
{
    Q_OBJECT

public:
    Receiver(QWidget *parent = 0);

private slots:
    void processPendingDatagrams();

private:
    QLabel *statusLabel;
    QPushButton *quitButton;
    QUdpSocket *udpSocket;
};

receiver.cpp

#include <QtWidgets>
#include <QtNetwork>

#include "receiver.h"

Receiver::Receiver(QWidget *parent)
    : QWidget(parent)
{
    statusLabel = new QLabel(tr("监听 广播 信息"));
    statusLabel->setWordWrap(true);

    quitButton = new QPushButton(tr("&Quit"));

    udpSocket = new QUdpSocket(this);
    udpSocket->bind(45454, QUdpSocket::ShareAddress);

    connect(udpSocket, SIGNAL(readyRead()),
            this, SLOT(processPendingDatagrams()));

    connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));

    QHBoxLayout *buttonLayout = new QHBoxLayout;
    buttonLayout->addStretch(1);
    buttonLayout->addWidget(quitButton);
    buttonLayout->addStretch(1);

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(statusLabel);
    mainLayout->addLayout(buttonLayout);
    setLayout(mainLayout);

    setWindowTitle(tr("广播 接收"));
}

void Receiver::processPendingDatagrams()
{
    while (udpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        udpSocket->readDatagram(datagram.data(), datagram.size());
        statusLabel->setText(tr("接收 数据: \"%1\"")
                             .arg(datagram.data()));
    }
}

效果

默认显示如下:
在这里插入图片描述
当点击发送时:
在这里插入图片描述

结论

青春就像一只容器,装满了不安躁动青涩与偶尔的疯狂


http://www.niftyadmin.cn/n/5268590.html

相关文章

聚类分析实例

目录 层次聚类概述 自底向上的合并算法 相似度计算 实例 分别计算欧式距离值&#xff08;矩阵&#xff09; 两个组合数据点间的距离 层次聚类实例 K-MEANS 算法 基本概念 工作流程 K-Means算法实例 K值对结果的影响 DBSCAN 算法 算法步骤 基本步骤 工作流程 参…

javaEE -17(13000字 CSS3 入门级教程)

一&#xff1a;CSS3 简介 CSS3 是 CSS2 的升级版本&#xff0c;它在 CSS2 的基础上&#xff0c;新增了很多强大的新功能&#xff0c;从而解决一些实际面临的问题&#xff0c;CSS3 在未来会按照模块化的方式去发展&#xff1a;https://www.w3.org/Style/CSS/current-work.html …

Unity 使用Input.GetAxis(“Horizontal/Vertical“)移动鼠标没反应的原因

在Unity中&#xff0c;当我们使用Input.GetAxis("Horizontal")和Input.GetAxis("Vertical")通过鼠标移动的返回数值以控制物体移动或其它操作时&#xff0c;却没有反应&#xff0c;令人费解。 首先我们获取返回数值并打印&#xff1a; float horizontal …

【Flink-Sql-Kafka-To-ClickHouse】使用 FlinkSql 将 Kafka 数据写入 ClickHouse

【Flink-Sql-Kafka-To-ClickHouse】使用 FlinkSql 将 Kafka 数据写入 ClickHouse 1&#xff09;需求分析2&#xff09;功能实现3&#xff09;准备工作3.1.Kafka3.2.ClickHouse 4&#xff09;Flink-Sql5&#xff09;验证 1&#xff09;需求分析 1、数据源为 Kafka&#xff0c;定…

Python数据科学视频讲解:Python字典

2.13 Python字典 视频为《Python数据科学应用从入门到精通》张甜 杨维忠 清华大学出版社一书的随书赠送视频讲解2.13节内容。本书已正式出版上市&#xff0c;当当、京东、淘宝等平台热销中&#xff0c;搜索书名即可。内容涵盖数据科学应用的全流程&#xff0c;包括数据科学应用…

大 O 表示法在机器学习中的重要性

一、介绍 在不断发展的机器学习领域&#xff0c;算法的效率至关重要。大 O 表示法成为这方面的一个关键工具&#xff0c;它提供了一种描述算法性能或复杂性的语言&#xff0c;特别是在时间和空间方面。本文探讨了 Big O 表示法在机器学习中的重要性&#xff0c;阐明了它在算法选…

phpstudy是什么?

PHPStudy 是一个集成环境工具&#xff0c;它将 PHP 开发所需的软件&#xff0c;如 Apache&#xff08;Web服务器&#xff09;、MySQL&#xff08;数据库服务器&#xff09;、PHP&#xff08;脚本语言&#xff09;等打包在一起&#xff0c;以便用户能够轻松安装和配置这些软件&a…

【halcon深度学习】目标检测的数据准备过程中的一个库函数determine_dl_model_detection_param

determine_dl_model_detection_param “determine_dl_model_detection_param” 直译为 “确定深度学习模型检测参数”。 这个过程会自动针对给定数据集估算模型的某些高级参数&#xff0c;强烈建议使用这一过程来优化训练和推断性能。 过程签名 determine_dl_model_detection…