【Qt】Qt 网络 | UDP Socket

news2024/9/23 19:27:43

文章目录

  • 核心API
  • 代码示例
    • 服务器
    • 客户端

要使用 Qt 网络编程,需要在项目中的 .pro 文件中添加 network 模块
在这里插入图片描述

核心API

Qt 的 UDP Socket 主要的类有两个 QUdpSocketQNetworkDatagram
因为是 UDP 是面向数据报的,QNetworkDatagram 就是对 数据报的封装,内容包括:对端发送的数据,对端的 IP 和 端口号

QUdpSocket 表示一个 UDP 的 socket 文件

名称类型说明对标原生API
bind(const QHostAddress &address, quint16 port = 0)方法绑定指定的 IP地址 和 端口号bind
receiveDatagram()方法返回 QNetworkDatagram 读取一个 UDP 数据报recvfrom
writeDatagram(const QNetworkDatagram &datagram)方法发送一个 UDP 数据报sendto
writeDatagram(const char *data, qint64 size, const HostAddress &address, quint16 port)方法data是要发送的数据,size是数据的长度,address是目标 IP地址,port是目标端口号sendto
readyRead信号在收到数据并准备就绪后触发类似于 IO 多路复用的通知机制

QNetworkDatagram 表示一个 UDP 数据报

名称类型说明对标原生API
QNetworkDatagram(const QByteArray &data, const QHostAddress &destinationAddress = QHostAddress(), quint16 port = 0)构造函数通过 QByteArray,目标 IP地址,目标端口号构造一个 UDP 数据报,通常用于发送数据
data()方法获取数据报内部持有的数据,返回 QByteArray
senderAddress()方法获取数据报中包含的对端的IP地址recvfrom 包含了该功能
senderPort()方法获取数据报中包含的对端的端口号recvfrom 包含了该功能

代码示例

通过模拟 客户服务器的UDP通信 熟悉上述方法使用
客户端通过输入栏获取数据,点击按钮发送给服务端
服务端接受客户端数据,并返回相同数据,验证通信无误

服务器

  1. 创建界面,包含一个 QListWidget 用来显示消息
    在这里插入图片描述
  2. 创建 QUdpSocket 成员,修改 widget.h
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
//槽函数
public slots:
    void handleRequest();//处理客户端请求
private:
    QString process(const QString &request);//业务处理逻辑
private:
    Ui::Widget *ui;
    QUdpSocket *socket;//套接字
};
  1. 编写 widget.cpp,实现相关方法

因为 UDP 是无连接的,绑定端口号后就可以接受数据了,所以要先对 readReady信号连接槽函数
逻辑如下:1. 设置窗口标题 2. 创建套接字 3. 连接信号槽 4. 绑定端口号

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //1. 设置窗口标题
    this->setWindowTitle("服务端");
    //2. 创建套接字
    socket = new QUdpSocket(this);
    //UDP绑定完就开启服务了,所以需要先连接信号槽
    //3. 连接信号槽
    connect(socket, &QUdpSocket::readyRead, this, &Widget::handleRequest);
    //4. 绑定,服务端绑定任意IP,端口号指定为9090
    bool ret = socket->bind(QHostAddress::Any, 9090);
    if(!ret)
    {
        QMessageBox::critical(this, "错误", "绑定套接字失败");
        return;
    }

}

编写 readReady 对应槽函数
逻辑如下:1. 获取用户数据报 2. 提取其中数据 3. 业务处理 4. 返回响应

void Widget::handleRequest()
{
    //1. 获取用户数据报
    const QNetworkDatagram requestDatagram = socket->receiveDatagram();
    //2. 提取其中数据
    QString request = requestDatagram.data();
    //3. 业务处理逻辑
    QString responce = process(request);
    //4. 记录客户端数据
    QString log = "[" + requestDatagram.senderAddress().toString() + ":" + QString::number(requestDatagram.senderPort())
                + "]  request:" + request + "  responce:" + responce;
    ui->listWidget->addItem(log);
    //5. 返回响应
    QNetworkDatagram responceDatagram(responce.toUtf8(), requestDatagram.senderAddress(), requestDatagram.senderPort());
    socket->writeDatagram(responceDatagram);
}

此处服务器的业务处理只是简单的回显数据

QString Widget::process(const QString &request)
{
    return request;
}

客户端

  1. 创建界面。包含 一个 QLineEditQPushButtonQListWidget
    通过布局管理器搭配,规范界面
    在这里插入图片描述
  2. 声明全局常量:服务端的 IP地址端口号
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 9090
  1. 创建 QUdpSocket 成员,修改 widget.h,定义成员
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    //按钮点击槽函数
    void on_pushButton_clicked();
    //客户端业务处理逻辑
    void handleRequest();
private:
    Ui::Widget *ui;
    QUdpSocket *socket;
};
  1. 修改 widget.cpp,初始化 socket
    客户端不需要绑定端口号
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->pushButton->setShortcut(QKeySequence(Qt::Key_Return));
    //设置窗口标题
    this->setWindowTitle("客户端");
    //创建套接字
    socket = new QUdpSocket(this);
    //连接信号槽
    connect(socket, &QUdpSocket::readyRead, this, &Widget::handleRequest);
}

按钮点击槽函数
逻辑如下:1. 获取输入栏文本 2. 记录发送信息 3. 将消息发送给服务端 4. 清空输入栏

void Widget::on_pushButton_clicked()
{
    //1. 获取输入栏的文本
    QString text = ui->lineEdit->text();
    QNetworkDatagram requestDatagram(text.toUtf8(), QHostAddress(SERVER_IP), SERVER_PORT);
    //2. 记录发送信息
    QString message = "发送:" + text;
    ui->listWidget->addItem(message);
    //3. 将消息发送给服务端
    socket->writeDatagram(requestDatagram);
    //4. 将输入栏清空
    ui->lineEdit->clear();
}

客户端业务处理函数

void Widget::handleRequest()
{
    //1. 获取服务端返回的数据报
    QNetworkDatagram responceDatagram = socket->receiveDatagram();
    QString responce = responceDatagram.data();
    //2. 显示消息
    ui->listWidget->addItem("接收:" + responce);
}

运行结果如下:
在这里插入图片描述

结束语
感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

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

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

相关文章

【项目管理】系统设计与开发管理规程(Word完整文件)

2 过程总体描述 2.1 过程概述 2.2 过程流程图 3 过程元素描述 3.1 产品方案 3.2 产品设计 3.3 产品实现 获取方式:本文末个人名片直接获取。 软件资料清单列表部分文档清单:工作安排任务书,可行性分析报告,立项申请审批表&#xf…

【模拟器-夜神】Mac卡在99%问题

▒ 目录 ▒ 🛫 导读需求 1️⃣ 首次启动提示2️⃣ 手动授权允许加载驱动非苹果CPU苹果CPU 📖 参考资料 🛫 导读 需求 解决模拟器中遇到的问题 ,汇总。 1️⃣ 首次启动提示 首次点击图标启动时会弹出提示: 解决方式如…

本地搭建XSS 漏洞接收平台实践分享

免责声明 本文仅限于学习讨论与技术知识的分享,不得违反当地国家的法律法规。对于传播、利用文章中提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本文作者不为此承担任何责任,一旦造成后果请自行承担&…

操作系统面试真题总结(二)

文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 栈空间和空间堆有什么区别?各自优缺点呢? …

diffusion 模型gguf量化使用案例,支持CPU运行

参考: https://github.com/leejet/stable-diffusion.cpp 在线demo使用: https://colab.research.google.com/drive/1NkAzSn3iYOwkY1Jy7qJfV_d2ZMHQmXrK?usp=sharing 一般gguf量化质量 fp16 > Q8 > fp8 > Q4 > Q4k_m > Q4k_s > nf4 安装 !git clone --r…

[H贪心] lc3273. 对 Bob 造成的最少伤害(贪心+排序+推公式+双周赛138_4)

文章目录 1. 题目来源2. 题目解析 1. 题目来源 链接:3273. 对 Bob 造成的最少伤害 题单: na na 2. 题目解析 略低于正常难度的 T4。 显然我们应该尽可能的将伤害高的先消掉,然后写完代码就会发现 WA 了。想太简单了,那就推…

如何在JPG文件中隐写数据

概述 最近在做资源管理器背景的一个功能时,需要将信息传递到DLL中去, 主要就是传递一些比较简单的参数,包括图片的契合度,透明度之类的。通信方式有多种,毕竟是练手的功能,就想找一些以前没用过的方式。 …

心觉:潜意识精准显化(一)开篇

Hi,我是心觉,与你一起玩转潜意识、脑波音乐和吸引力法则,轻松搞定人生挑战,实现心中梦想! 挑战日更写作156/1000(完整记录在下面) 公门洞开纳百川 众心逐梦越千山 号召引领潜力绽 心觉潜意识无间 每个人都渴望自…

psql常见报错解决

问题 解决 要在管理员模式下启动 pg_ctl start -D "D:\Program\PostgreSQL\data" 注册成服务 D:\Program\PostgreSQL\bin\pg_ctl.exe register -N "postgresql" -D "D:\Program\PostgreSQL\data" -U "postgres" -P "postgre…

华为 HCIP-Datacom H12-821 题库 (1)

有需要题库的可以看主页置顶 1.MSTP 有不同的端口角色,对此说法不正确的是: A、MSTP 中除边缘端口外,其他端口角色都参与 MSTP 的计算过程 B、MSTP 同一端口在不同的生成树实例中可以担任不同的角色。 C、MSTP 域边缘端口是指位于 MST 域的边…

桶排序【算法 14】

桶排序算法详解 桶排序(Bucket Sort)是一种基于分配的排序算法,适用于均匀分布在特定范围内的数据。其核心思想是将输入数据分到若干个桶(Bucket)中,每个桶分别进行排序,最后合并桶内的元素形成…

【STM32】BKP备份寄存器与RTC实时时钟

本篇博客重点在于标准库函数的理解与使用,搭建一个框架便于快速开发 目录 BKP简介 BKP代码注解 读写备份寄存器 复位备份寄存器 BKP代码 RTC简介 RTC代码注解 RTCCLK时钟源选择 分频器配置 时钟同步 RTC代码 MyRTC.h MyRTC.c main.c BKP简介 BKP&…

TeamTalk路由服务器

路由相关信令和协议设计 enum BuddyListCmdID {// ...... 暂时省略无关信令CID_BUDDY_LIST_USERS_STATUS_REQUEST 522,CID_BUDDY_LIST_USERS_STATUS_RESPONSE 523,// ...... 暂时省略无关信令 };message IMUsersStatReq{//cmd id: 0x020arequired uint32 user_id 1;repeat…

JS设计模式之“名片设计师” - 工厂方法模式

image.png 前言 上篇文章我们了解到什么是简单工厂模式,请参考上篇文章:JS设计模式之 “神奇的魔术师” - 简单工厂模式,不过这是工厂中最简单的一种,本篇文章我们将同大家一起认识一种更复杂的工厂模式,它将给我们提…

【Kubernetes】声明式创建各种资源

k8s声明式创建 kubernetes陈述式创建与声明式创建yaml各个字段含义Pod yaml文件详解deployment.yaml文件详解server.yaml文件详解 k8s中port的区别1、声明式创建pod label包含app: zhangsan2、声明式创建deployment,包含3个nginx副本,label包含app: zhan…

【MyBatis】MyBatis的一级缓存和二级缓存简介

目录 1、一级缓存 1.1 我们在一个 sqlSession 中,对 User 表根据id进行两次查询,查看他们发出sql语句的情况。 1.2 同样是对user表进行两次查询,只不过两次查询之间进行了一次update操作。 1.3 一级缓存查询过程 1.4 Mybatis与Spring整…

Windows10上安装PostgreSQL 16

PostgreSQL是一个先进的、开源的、免费的、功能强大的关系型数据库,它使用并扩展了SQL语言,并结合了许多功能,可以安全地存储和扩展复杂的数据工作负载。PostgreSQL可在Windows、Linux、macOS等多个平台上运行,License使用Postgre…

hive学习(五)

一、hive的DML操作 1.load(向表中装载数据) hive> load data [local] inpath 路径 [overwrite] into table 表名 [partition (partcol1val1,…)];特殊说明 1)local:标识从本地加载数据到Hive表,若没有local的话从…

Linux系统下KubeSphere3.4.1离线安装包制作及部署过程

一、概述 KubeSphere 是 GitHub 上的一个开源项目,是成千上万名社区用户的聚集地。很多用户都在使用 KubeSphere 运行工作负载。对于在 Linux 上的安装,KubeSphere 既可以部署在云端,也可以部署在本地环境中,例如 AWS EC2、Azure…

JS设计模式之“幽灵工厂” - 抽象工厂模式

image.png 一. 了解带头模范 - 抽象类 JavaScript中并没有原生的抽象类的概念,但可以通过一些方式来模拟实现抽象类的效果。 抽象类是一种不能被直接实例化的类,只能作为其他类的基类使用。它定义了一组抽象方法,子类必须实现这些抽象方法。…