【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()));
    }
}

效果

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

结论

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/250578.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

白日门引擎传奇手游架设教程-GM的成长之路

准备工具 服务器一台&#xff08;Windows系统&#xff09;白日门引擎服务端版本一个 前言&#xff1a; 此次教程使用的是版本是一个决战斗罗的一个版本、服务器使用的是驰网科技的游戏高频系列服务器。 教程开始 在我们拿到版本之后、我们需要先把版本解压到服务器D盘的根目录…

Mac安装Typora实现markdown自由

一、什么是markdown Markdown 是一种轻量级标记语言&#xff0c;创始人为约翰格鲁伯&#xff08;John Gruber&#xff09;。 它允许人们使用易读易写的纯文本格式编写文档&#xff0c;然后转换成有效的 XHTML&#xff08;或者HTML&#xff09;文档。这种语言吸收了很多在电子邮…

RocketMQ系统性学习-SpringCloud Alibaba集成RocketMQ以及顺序消费实战

顺序消费实战 顺序消费分为两种&#xff1a; 全局有序&#xff1a;适用于并发度不大&#xff0c;并且对消息要求严格一致性的场景下 通过创建一个 topic&#xff0c;并且该 topic 下只有一个队列&#xff0c;那么生产者向着一个队列中发消息&#xff0c;消费者也在这一个队列中…

Redis-数据结构

参考资料 极客时间Redis&#xff08;亚风&#xff09; Redis数据结构 SDS sds(Simple Dynamic String) 字符串接结构体: struct --attribute_- ((-_packed__)) sdshdr8{uint8_t len&#xff1b;/* buf已保祥的字符串字节数&#xff0c;不包含结束标示*/uint8_t alloc&#…

正式开通运营!“一应黔行”服务网点进驻贵阳地铁3号线

今天下午14:00&#xff0c;贵阳地铁3号线正式进入初期运营。为进一步实现一卡通在贵阳市全区域覆盖&#xff0c;不断提升“一应黔行一卡通”业务办理效率&#xff0c;贵阳市信捷科技有限公司在贵阳地铁3号线明珠大道站、顺海站、皂角井站3个站点设立“一应黔行”服务网点&#…

[Spring ~松耦合的设计神器]`SPI`

Java SPI&#xff08;Service Provider Interface&#xff09;是一种Java的服务提供者接口机制。它允许在运行时动态加载实现服务接口的类。 文章目录 基本概念最简单的实例使用 jar 包通过 spi动态实现接口功能 基本概念 SPI 机制的基本思想是&#xff0c;定义一个服务接口&a…

基于ssm线上学习网站论文

线上学习网站 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;作为学校以及一些培训机构&#xff0c;都在用信息化战术来部署线上学习以及线上考试&#xff0c;可以与线下的考试有机的结合在一起&#xff0c;实现线上学习网站在技术上已成熟。本文介绍了线上学…

【Android开发-25】Android中多线程编程用法介绍

1&#xff0c;线程基本用法 在Android中&#xff0c;线程的使用主要有两种方法&#xff1a;一种是扩展java.lang.Thread类&#xff0c;另一种是实现Runnable接口。 1.1以下是一个简单的Android线程继承Thread的用法示例&#xff1a; public class MyThread extends Thread {…

maven+spock

pom配置 话说JunitMockito的组合用起来是真难用&#xff0c;还是Spock的简单&#xff0c;尤其是参数化的测试。junit的Parameter是鸡肋&#xff0c;杂恶心&#xff1b;Theories用来也不爽。 <?xml version"1.0" encoding"UTF-8"?><project xm…

SoloLinker第一次使用记录,解决新手拿到板子的无所适从

本文目录 一、简介二、进群获取资料2.1 需要下载资料2.2 SDK 包解压 三、SDK 编译3.1 依赖安装3.2 编译配置3.3 启动编译3.4 编译后的固件目录 四、固件烧录4.1 RV1106 驱动安装4.2 打开烧录工具4.3 进入boot 模式&#xff08;烧录模式&#xff09;4.4 烧录启动固件4.5 烧录升级…

Spring入门

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

设计模式——组合模式(结构型)

引言 组合模式是一种结构型设计模式&#xff0c; 你可以使用它将对象组合成树状结构&#xff0c; 并且能像使用独立对象一样使用它们。 问题 如果应用的核心模型能用树状结构表示&#xff0c; 在应用中使用组合模式才有价值。 例如&#xff0c; 你有两类对象&#xff1a; ​…

Graphics Profiler 使用教程

GraphicsProfiler 使用教程 1.工具简介&#xff1a;2.Navigation介绍2.1.打开安装好的Graphics Profiler。2.2.将手机连接到计算机&#xff0c;软件会在手机中安装一个GraphicsProfiler应用(该应用是无界面的&#xff09;。2.3.Show files list2.4.Record new trace2.4.1.Appli…

java --- 集合进阶

目录 一、单列集合顶层接口 Collection 1.1 基本方法 1.2 Collection 的遍历方式 二、list集合 1.2 ArrayList Vector 底层结构 1.3 LinkedList ArrayList 和 LinkedList 比较 三、set接口 3.1、Set 接口和常用方法 3.2 HashSet HashSet 底层机制&#xff08;HashMap…

Python 直观理解基尼系数

基尼系数最开始就是衡量人群财富收入是否均衡&#xff0c;大家收入平平&#xff0c;那就是很平均&#xff0c;如果大家收入不平等&#xff0c;那基尼系数就很高。 还是给老干部们讲的言简意赅。 什么是基尼系数 我们接下来直接直观地看吧&#xff0c;程序说话 # -*- coding:…

万兆网络之屏蔽线序接法(上)

可以经常听到用RJ45指代网线&#xff0c;用RJ11指代电话线的&#xff0c;RJ&#xff08;Registered Jack&#xff09;即已注册插口&#xff0c;可以简单理解为一种约定就行&#xff08;参见参考链接&#xff09; 前一篇已经讲到&#xff0c;网线线对互相缠绕是为了电流方向相反…

CSRF(跨站脚本请求)

一、漏洞原理 CSRF&#xff08;Cross-Site Request Forgery&#xff09;是一种网络安全攻击&#xff0c;攻击者通过欺骗用户在不知情的情况下发送请求&#xff0c;从而实现对目标网站的操作。 网站管理员(已经登录网站后台)——黑客构造的恶意服务器(是网站的创建用户请求)——…

(第6天)RHEL 8 安装单机 Oracle 19C CDB 数据库

RHEL 8 安装单机 Oracle 19C 数据库(第6天) 随着 Oracle 版本的升级,硬件也在不断更新迭代,为了迎合这种趋势,Linux 系统也在不断升级,目前已经更新至 8 代版本。相信不久的将来,Linux 8 和 Oracle 19C 将成为主流版本,因此不得不讲 Linux 8 如何安装 Oracle 19C 数据…

K8s投射数据卷

目录 一.Secret 1.secret介绍 2.secret的类型 3.创建secret 4.使用secret 环境变量的形式 volume数据卷挂载 二ConfigMap 1.创建ConfigMap的方式 2.使用ConfigMap 2.1作为volume挂载使用 2.2.作为环境变量 三.Downward API 1.以环境变量的方式实现 2.Volume挂载 一.S…

C++相关闲碎记录(16)

1、正则表达式 &#xff08;1&#xff09;regex的匹配和查找接口 #include <regex> #include <iostream> using namespace std;void out (bool b) {cout << ( b ? "found" : "not found") << endl; }int main() {// find XML/H…