QT 学习笔记(十五)

news2024/12/23 23:08:17

文章目录

  • 一、UDP 通信过程
    • 1. Linux 下的 UDP 通信过程
    • 2. QT 下的 UDP 通信过程
    • 3. 在 QT 中实现 UDP 通信的流程
    • 4. TCP/IP 和 UDP的区别
  • 二、UDP 文本发送
    • 1. UDP 文本发送实例演示
    • 2. UDP 广播
    • 3. UDP 组播
  • 三、UDP 文本发送实现代码
    • 1. 主窗口头文件 widget.h
    • 2. 主窗口源文件 widget.cpp
  • 四、QTimer 定时器的使用
    • 1. QTimer 定时器使用实例演示
    • 2. QTimer 定时器使用实现代码
      • 2.1 主窗口头文件 widget.h
      • 2.1 主窗口源文件 widget.cpp

由于每次代码都是在原有程序上修改,因此除了新建项目,不然一般会在学完后统一展示代码。
提示:具体项目创建流程和注意事项见QT 学习笔记(一)
提示:具体项目准备工作和细节讲解见QT 学习笔记(二)

一、UDP 通信过程

1. Linux 下的 UDP 通信过程

在这里插入图片描述

2. QT 下的 UDP 通信过程

在这里插入图片描述

  • 在过程当中,使用 QT 提供的 QUdpSocket 进行 UDP 通信。
  • 在 UDP 方式下,客户端并不与服务器建立连接,它只负责调用发送函数向服务器发送数据。类似的服务器也不从客户端接收连接,只负责调用接收函数,等待来自客户端的数据的到达。

3. 在 QT 中实现 UDP 通信的流程

  • 在 UDP 通信中,服务器端和客户端的概念已经显得有些淡化,两部分做的工作都大致相同:
  • (1) 创建套接字。
  • (2) 绑定套接字(包括下面两部分):
  • 第一部分:在 UDP 中如果需要接收数据则需要对套接字进行绑定,只发送数据则不需要对套接字进行绑定。
  • 第二部分:通过调用 bind() 函数将套接字绑定到指定端口上。
  • (3) 接收或者发送数据
  • 接收数据介绍如下:使用 readDatagram() 接收数据,函数声明如下:
qint64	readDatagram(char * data, qint64 maxSize, 
QHostAddress * address = 0, quint16 * port = 0)
  • 该函数声明的参数介绍如下:
参数含义
data接收数据的缓存地址
maxSize:缓存接收的最大字节数
address:数据发送方的地址(一般使用提供的默认值)
port:数据发送方的端口号(一般使用提供的默认值)
  • 使用 pendingDatagramSize() 可以获取到将要接收的数据的大小,根据该函数返回值来准备对应大小的内存空间存放将要接收的数据。
  • 发送数据介绍如下: 使用 writeDatagram() 函数发送数据,函数声明如下:
qint64	writeDatagram(const QByteArray & datagram, 
const QHostAddress & host, quint16 port)
  • 该函数声明的参数介绍如下:
参数含义
datagram要发送的字符串
host数据接收方的地址
port数据接收方的端口号

4. TCP/IP 和 UDP的区别

TCP/IPUDP
是否连接面向连接无连接
传输方式基于流基于数据报
传输可靠性可靠不可靠
传输效率效率低效率高
能否广播不能

二、UDP 文本发送

  • 生成一个新的项目,具体步骤过程见提示。

1. UDP 文本发送实例演示

  • 在 UDP 通信的过程当中,没有服务器端和客户端之分,二者集成为一个东西。
  • 在生成新项目的过程中,我们选择基类为 QWidget ,这是因为 QWidget 当中比较干净,不存在别的东西,而 QMainWindow 虽然也可以实现,但其中存在工具栏,菜单栏,核心控件等东西,比较复杂。
  • 首先,我们在 ui 界面布置出所需要的窗口界面,包含两个标签(分别是对方的 IP 和对方的端口)以及对应的行编辑区,两个按钮(发分别是送 send 和 关闭 close)和一个文本编辑区(用来输入和显示),具体界面布局如下图所示。

在这里插入图片描述

  • 随后,我们在 UDP.pro 当中加入 QT += network 代码,以便后续工作可以顺利开展。
  • 这里使用传统的 connect 函数,通过编写槽函数实现,不选择使用 Lambda 表达式,这里需要注意的是由于信号没有参数,所以槽函数也没有参数。
  • 先进行接收信息槽函数的代码编写,具体实现代码如下。
//接收数据的槽函数
void Widget::dealMsg()
{
    //先读取对方发送的内容
    char buf[1024] = {0};
    QHostAddress cliAddr;    //对方地址
    quint16 port;    //对方端口
    qint64 len = udpsocket->readDatagram(buf,sizeof(buf),&cliAddr,&port);
    if(len > 0)
    {
        //格式化 [192.68.2.2;8888]aaaa
        QString str = QString("[%1:%2] %3")
                .arg(cliAddr.toString())
                .arg(port)
                .arg(buf);
        //给编辑区设置内容
        ui->textEdit->setText(str);
    }
}
  • 然后,在 ui 界面通过按钮 send 转到槽函数操作,进行发送信息的代码编写,具体实现代码如下。
//发送按钮
void Widget::on_pushButtonsend_clicked()
{
    //先获取对方的IP和端口
    QString ip = ui->lineEditIP->text();
    qint16 port = ui->lineEditport->text().toInt();

    //获取编辑区内容
    QString str = ui->textEdit->toPlainText();

    //给指定的IP发送数据
    udpsocket->writeDatagram(str.toUtf8(),QHostAddress(ip),port);
}
  • 在完成代码编写后,我们就会得到一个 UDP 通信界面,通过输入别人的 IP 和端口(为自己设定),便可以进行 UDP 通信。

在这里插入图片描述

  • 在这里只有我自己的一个 IP 和端口,没有别人的进行通信,故具体现象无法展示。

2. UDP 广播

  • 使用 UDP 广播发送消息的时候会发给所有用户。
  • 在使用 QUdpSocket 类的 writeDatagram() 函数发送数据的时候,其中第二个参数 host 应该指定为广播地址:QHostAddress::Broadcast 此设置相当于 QHostAddress(“255.255.255.255”)。
  • 使用 UDP 广播的的特点:
  • (1) 使用 UDP 进行广播,局域网内的其他的 UDP 用户全部可以收到广播的消息。
  • (2) UDP 广播只能在局域网范围内使用。

3. UDP 组播

  • 我们再使用广播发送消息的时候会发送给所有用户,但是有些用户是不想接受消息的,这时候我们就应该使用组播,接收方只有先注册到组播地址中才能收到组播消息,否则则接受不到消息。
  • 另外组播是可以在 Internet 中使用的。
  • 在使用 QUdpSocket 类的 writeDatagram() 函数发送数据的时候,其中第二个参数 host 应该指定为组播地址,关于组播地址的分类介绍如下。
地址含义
224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用。
224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet。
224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效。
239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。
  • 注册加入到组播地址需要使用 QUdpSocket 类的成员函数:
bool joinMulticastGroup(const QHostAddress & groupAddress)
  • 但是如果我们直接加入某个组播时,会出现如下情况,虽然可以编译通过,但仍存在错误。

在这里插入图片描述

  • 对此,我们按照错误描述进行修改,用 QHostAddress::AnyIPv4 代替最开始绑定的地址即可。
//绑定
//udpsocket->bind(8888);
udpsocket->bind(QHostAddress::AnyIPv4,8888);

三、UDP 文本发送实现代码

1. 主窗口头文件 widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QUdpSocket>//UDP套接字

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

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

    //槽函数,处理对方发过来的数据(因为信号没有参数,所以槽函数也没有参数)
    void dealMsg();

private slots:
    void on_pushButtonsend_clicked();

private:
    Ui::Widget *ui;

    //UDP套接字
    QUdpSocket *udpsocket;
};

#endif // WIDGET_H

2. 主窗口源文件 widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QHostAddress>

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

    //分配空间,指定父对象(便于回收空间)
    udpsocket = new QUdpSocket(this);

    //绑定
    //udpsocket->bind(8888);
    udpsocket->bind(QHostAddress::AnyIPv4,8888);

    //加入某个组播
    //组播地址是D类地址
    udpsocket->joinMulticastGroup(QHostAddress("224.0.0.2"));
    //退出组播
    //udpsocket->leaveMulticastGroup();

    //标题
    setWindowTitle("服务器端口为:8888");

    //当对方成功发送数据过来
    //自动触发 readyRead()
    connect(udpsocket,&QUdpSocket::readyRead,this,&Widget::dealMsg);

}

//接收数据的槽函数
void Widget::dealMsg()
{
    //先读取对方发送的内容
    char buf[1024] = {0};
    QHostAddress cliAddr;    //对方地址
    quint16 port;    //对方端口
    qint64 len = udpsocket->readDatagram(buf,sizeof(buf),&cliAddr,&port);
    if(len > 0)
    {
        //格式化 [192.68.2.2;8888]aaaa
        QString str = QString("[%1:%2] %3")
                .arg(cliAddr.toString())
                .arg(port)
                .arg(buf);
        //给编辑区设置内容
        ui->textEdit->setText(str);
    }
}

Widget::~Widget()
{
    delete ui;
}

//发送按钮
void Widget::on_pushButtonsend_clicked()
{
    //先获取对方的IP和端口
    QString ip = ui->lineEditIP->text();
    qint16 port = ui->lineEditport->text().toInt();

    //获取编辑区内容
    QString str = ui->textEdit->toPlainText();

    //给指定的IP发送数据
    udpsocket->writeDatagram(str.toUtf8(),QHostAddress(ip),port);
}

四、QTimer 定时器的使用

  • 生成一个新的项目,具体步骤过程见提示。

1. QTimer 定时器使用实例演示

  • 这里不需要在 ui 界面进行布局操作,可以直接对 QTimer 定时器进行使用。
  • QTimer 定时器需要位于 ui 界面的 Display Widgets 当中的 LCD Number 和两个按钮(分别是 start 和 stop),具体界面如下图所示。

在这里插入图片描述

  • 首先,我们需要创建一个定时器对象。
  • 随后,当我们按下按钮 start 开始计时,每过设定的时间间隔自动触发 timeout() ,按下按钮 stop 结束计时(这中间使用 Lambda 表达式,需要提前在 QTimer.pro 当中加入 CONFIG += C++11 代码)。
  • 对两个按钮分别进行转到槽函数的操作,进行代码的编写。
  • 当我们按下按钮 start 时,QTimer 定时器的开始启动,其具体现象如下图所示。

在这里插入图片描述

  • 当我们按下按钮 stop 时,QTimer 定时器的停止工作,这里再次点击按钮 start,QTimer 定时器仍会继续启动,其具体现象如下图所示。

在这里插入图片描述

2. QTimer 定时器使用实现代码

2.1 主窗口头文件 widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
//定时器对象头文件
#include <QTimer>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_pushButton_clicked();

    void on_pushButtonstop_clicked();

private:
    Ui::Widget *ui;

    //创建定时器对象
    QTimer *mytimer;
};

#endif // WIDGET_H

2.1 主窗口源文件 widget.cpp

#include "widget.h"
#include "ui_widget.h"

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

    mytimer = new QTimer(this);

    connect(mytimer,&QTimer::timeout,
            [=]()
            {
                static int i = 0;
                i++;
                ui->lcdNumber->display(i);
            }
            );
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    //启动定时器
    //时间间隔为100ms
    //每隔100ms,定时器mytimer内容自动触发timeout()
    //如果定时器没有激活才启动
    if(mytimer->isActive() == false)
    {
        mytimer->start(100);
    }    
}

void Widget::on_pushButtonstop_clicked()
{
    //如果定时器已经激活才关闭
    if(true == mytimer->isActive())
    {
        mytimer->stop();
    }
}    

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文创新及观点

FEW-SHOT TEXT CLASSIFICATION WITH DISTRIBUTIONAL SIGNATURES 任务 Given an N-way K-shot classification task 论文设计图像 数据集 20 Newsgroups is comprised of informal discourse from news discussion forums (Lang, 1995).Documents are organized under 20 to…

数据分析-深度学习 Day2

目录&#xff1a;第一节 机器学习&深度学习介绍第二节 机器学习攻略一、机器学习的框架二、模型训练攻略三、针对Optimization Issue的优化&#xff0c;类神经网络训练不起来怎么办(一) 局部最优点和鞍点(二) 批处理和momentum(三) 自动调节学习率Learning rate(四) 损失函…

vue实现微信端和企业微信端扫码

前要&#xff1a;微信端调用微信的扫一扫和企业微信端调用企业微信的扫一扫获取订单码查询&#xff01;&#xff01; 一、微信端扫一扫 这里使用的是uniapp框架调用微信的内置sdk扫码防伪溯源&#xff01;http引入或者npm安装模块&#xff1a; //public/index.html <!DOCT…

《设计模式》命令模式

《设计模式》设计模式的基本原则 《设计模式》单例模式 《设计模式》工厂模式 《设计模式》原型模式 《设计模式》建造者模式 《设计模式》适配器模式 《设计模式》桥接模式 《设计模式》装饰者模式 《设计模式》组合模式 《设计模式》外观模式 《设计模式》享元模式 《设计模式…

【Java开发】Spring Cloud 03 :Spring Boot 项目搭建

为了体验从 0 到 1 的微服务改造过程&#xff0c;我们先使用 Spring Boot 搭建一个基础版的优惠券平台项目&#xff0c;等学习到 Spring Cloud 的时候&#xff0c;我们就在这个项目之上做微服务化改造&#xff0c;将 Spring Cloud 的各个组件像添砖加瓦一样集成到项目里。上一章…

jacoco:java代码覆盖率实践

文章目录一、jacoco基本了解二、实践准备三、jacoco使用3.1 插桩3.2 dump:覆盖率文件导出3.3 report:可视化报告3.4 merge:合并覆盖率文件四、相关命令扩展4.1 javaagent4.2 dump4.3 merge4.4 report五、资源链接一、jacoco基本了解 jacoco是一款面向java的代码覆盖率工具&…

linux系统中C++中构造与析构函数以及this的使用方法

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;C里面的基本语法结构以及对应的操作方法。 目录 第一&#xff1a;构造函数与析构函数 第二&#xff1a;this指针 第一&#xff1a;构造函数与析构函数 什么是构造函数&#xff1f;构造函数在对象实例化时被系统自动调用&a…

xshell连接Linux一直失败解决方法

文章目录解决对象方法配置防火墙关闭Linux防火墙关闭Windows防火墙xshell连接Linux一直失败解决方法 解决对象 可能出现以下两个问题&#xff1a; Linux防火墙已关闭和Windows防火墙已经关闭配置好 vim /etc/sysconfig/network-scripts/ifcfg-ens33 方法 配置 这个是最容易…

linux系统中实现C++中继承和重载的方法

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;如何实现C中继承和重载的功能。 第一&#xff1a;C中的继承功能 面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类&#xff0c;这使得创建和维护一个应用程序变得更容易。这样做&#xff0…

CLRNet: Cross Layer Refinement Network for Lane Detection

Paper name CLRNet: Cross Layer Refinement Network for Lane Detection Paper Reading Note URL: https://arxiv.org/pdf/2203.10350.pdf TL;DR CVPR 2022 文章&#xff0c;自动驾驶公司飞步科技与浙大联合出品。lane anchor-based 方案&#xff0c;在多个数据集上取得 …

Linux中的哈希表:基于双链表的内核模块

1. 前言Linux内核中选取双向链表作为其基本的数据结构&#xff0c;并将其嵌入到其他的数据结构中&#xff0c;使得其他的数据结构不必再一一实现其各自的双链表结构。实现了双链表结构的统一&#xff0c;同时可以演化出其他复杂数据结构。本文对linux中基于双链表实现的哈希表进…

java springboot+mybatis电影售票网站管理系统前台+后台设计和实现

java springbootmybatis电影售票网站管理系统前台后台设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言…

RS—|遥感数字图像处理编程练习(python)

目录一&#xff1a;模拟计算图像直方图和累计直方图二&#xff1a;计算图像的均值、标准差、相关系数和协方差三&#xff1a;利用模板进行卷积运算四&#xff1a;获取彩色图像的直方图五&#xff1a;图像直方图均衡化一&#xff1a;模拟计算图像直方图和累计直方图 ① 调用的p…

【雷达入门 | FMCW毫米波雷达系统的性能参数分析】

本文编辑&#xff1a;调皮哥的小助理 FMCW毫米波雷达系统的性能参数主要包含&#xff1a; (1)距离估计、距离分辨率、距离精度、最大探测距离; (2)速度估计、速度分辨率、速度精度、最大不模糊速度&#xff1b; (3)角度估计、角度分辨率、角度精度、最大角度范围。 分析以及…

微服务框架SpringCloud从入门到通神(持续更新)

SpringCloud——>SpringBoot——>JavaWeb 微服务技术栈导学1 哔站up黑马程序员主讲老师&#xff0c;一上来就给介绍了SpringCloud出现的背景&#xff1a;微服务是分布式架构的一种&#xff0c;分布式架构就是要把服务做拆分&#xff0c;而SpringCloud只是解决了服务拆分式…

FTP协议原理简析

FTP服务器默认使用TCP协议的20、21端口与客户端进行通信。21端口用于建立控制连接&#xff0c;并传输FTP指令。20端口用于建立数据连接&#xff0c;传输数据流。 一&#xff1a;FTP功能简介 1&#xff1a;FTP服务器能够进行档案的传输与管理功能&#xff1b; 2&#xff1a;可以…

招生简章 | 欢迎报考中科院空天院网络信息体系技术重点实验室(七室)

官方公众号链接&#xff1a;招生简章 | 欢迎报考中科院空天院网络信息体系技术重点实验室&#xff08;七室&#xff09; 招生简章 | 欢迎报考中科院空天院网络信息体系技术重点实验室&#xff08;七室&#xff09; 中国科学院空天信息创新研究院&#xff08;简称空天院&#x…

【实战篇】38 # 如何使用数据驱动框架 D3.js 绘制常用数据图表?

说明 【跟月影学可视化】学习笔记。 图表库 vs 数据驱动框架 图表库只要调用 API 就能展现内容&#xff0c;灵活性不高&#xff0c;对数据格式要求也很严格&#xff0c;但方便数据驱动框架需要手动去完成内容的呈现&#xff0c;灵活&#xff0c;不受图表类型对应 API 的制约…

Smart Finance成为火必投票竞选项目,参与投票获海量奖励

最近&#xff0c;Huobi推出了新一期的“投票上币”活动&#xff0c;即用户可以通过HT为候选项目投票&#xff0c;在投票截止后&#xff0c;符合条件的优质项目将直接上线Huobi。而Smart Finance成为了新一期投票上币活动的竞选项目之一&#xff0c;并备受行业关注&#xff0c;与…

C++ 命令模式

什么是命令模式&#xff1f; 将请求转换为一个包含与请求相关的所有信息的独立对象。从而使你可以用不同的请求方法进行参数化&#xff0c;并且能够对请求进行排队、记录请求日志以及撤销请求操作。命令模式属于行为设计模式 如何理解命令模式 命令模式很像我们订外卖&#…