Qt 5.14.2 学习记录 —— 이십일 Qt网络和音频

server/2025/2/4 10:17:19/

文章目录

  • 1、UDP
    • 带有界面的Udp服务器(回显服务器)
  • 2、TCP
    • 回显服务器
  • 3、HTTP客户端
  • 4、音频


和Linux的网络一样,Qt封装了Linux的网络API,即Socket API。网络编程是在应用层写,需要传输层支持,传输层有UDP和TCP,Qt对此有两套API。

Qt网络编程时需要在.pro文件添加network模块。

1、UDP

两个类QUdpSocket,QNetworkDatagram,后者就是数据报。

QUdpSocket

在这里插入图片描述

不过Qt不是用堵塞的,而是利用信号槽。当socket收到请求时,QUdpSocket就会触发这个readyRead信号,此时槽函数就能进行处理逻辑了,整体也就形成了事件驱动的网络编程。

QNetworkDatagram

在这里插入图片描述

带有界面的Udp服务器(回显服务器)

创建一个QWidget项目,放一个List Widget到界面中。

pro文件里

QT       += core gui network

服务端

// widget.h#include <QWidget>
#include <QUdpSocket>
#include <QNetworkDatagram>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private:Ui::Widget *ui;QUdpSocket* socket;void processRequest();QString process(const QString& request);
};// widget.cpp#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QMessageBox>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 加上this就挂上了对象树, 自动析构// 不加就在析构函数里写上delete socketsocket = new QUdpSocket(this);this->setWindowTitle("服务器");// 先连接信号槽再绑定端口号// 绑定好端口号那么请求就可以收到了connect(socket, &QUdpSocket::readyRead, this, &Widget::processRequest);// Any表示任何IP地址都可以识别到bool flag = socket->bind(QHostAddress::Any, 9090);if (!flag){QMessageBox::critical(this, "服务器启动出错", socket->errorString());return ;}
}Widget::~Widget()
{delete ui;
}void Widget::processRequest()
{// 读取请求并解析const QNetworkDatagram& requestDatagram = socket->receiveDatagram();QString request = requestDatagram.data();// data()返回一个QByteArray对象, 这个类型可以赋值给QString// 根据请求计算响应 (由于是回显服务器, 响应就是请求自身, 不需要计算)const QString& response = process(request);// 响应写回给客户端// toUtf8()取出QString内部的字节数组// 后面两个参数表明要发送到哪个主机的哪个端口号QNetworkDatagram responseDatagram(response.toUtf8(), requestDatagram.senderAddress(), requestDatagram.senderPort());// 发送socket->writeDatagram(responseDatagram);// 交互的信息显示到界面上QString log = "[" + requestDatagram.senderAddress().toString() + ":" + QString::number(requestDatagram.senderPort()) + "] req: " + request + ", resp: " + response;ui->listWidget->addItem(log);
}QString Widget::process(const QString &request)
{// 回显服务器中响应和请求完全一样return request;
}

客户端,在同一目录下再创建一个QWidget项目即可。界面

在这里插入图片描述

如何做出这个界面就不写了,重点在客户端代码上

// widget.h#include <QWidget>
#include <QUdpSocket>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();void processResponse();private:Ui::Widget *ui;QUdpSocket* socket;
};// widget.cpp#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QNetworkDatagram>const QString& SERVER_IP = "127.0.0.1";
// 端口号本质是一个2字节的无符号整数
// quint16是Qt的unsigned short, 其大小是2个字节
const quint16 SERVER_PORT = 9090;Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);socket = new QUdpSocket(this);this->setWindowTitle("客户端");// 处理服务器返回的数据connect(socket, &QUdpSocket::readyRead, this, &Widget::processResponse);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{// 获取输入框内容const QString& text = ui->lineEdit->text();// 构造UDP请求数据QNetworkDatagram requestDatagram(text.toUtf8(), QHostAddress(SERVER_IP), SERVER_PORT);// 发送请求数据socket->writeDatagram(requestDatagram);// 发送的请求添加到列表框中ui->listWidget->addItem("客户端内容: " + text);// 输入框清空ui->lineEdit->setText("");
}void Widget::processResponse()
{// 读取响应const QNetworkDatagram& responseDatagram = socket->receiveDatagram();QString response = responseDatagram.data();// 显示ui->listWidget->addItem("服务器响应: " + response);
}

2、TCP

QTcpServer

在这里插入图片描述
在这里插入图片描述

QTcpScket

在这里插入图片描述

回显服务器

服务端,放一个List Widget到界面上

// widget.h#include <QWidget>
#include <QTcpServer>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void processConnection();QString process(const QString request);private:Ui::Widget *ui;QTcpServer* tcpServer;
};// widget.cpp#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QMessageBox>
#include <QTcpSocket>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->setWindowTitle("服务器");//创建QTcpServer实例tcpServer = new QTcpServer(this);// 接收响应的处理函数connect(tcpServer, &QTcpServer::newConnection, this, &Widget::processConnection);// 绑定并监听端口号bool flag = tcpServer->listen(QHostAddress::Any, 9090);if (!flag){QMessageBox::critical(this, "服务器启动失败!", tcpServer->errorString());exit(1);}
}Widget::~Widget()
{delete ui;
}void Widget::processConnection()
{// 通过tcpServer拿到socket对象, 用于和客户端进行通信QTcpSocket* clientSocket = tcpServer->nextPendingConnection();QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] 客户端上线!";ui->listWidget->addItem(log);// 处理客户端的请求connect(clientSocket, &QTcpSocket::readyRead, this, [=]() {// 返回的是QByteArray, 通过赋值转为QStringQString request = clientSocket->readAll();// 由于是回显服务器, 请求就是响应const QString& response = process(request);clientSocket->write(response.toUtf8());QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] " + " req: " + request + ", resp: " + response;ui->listWidget->addItem(log);});// 客户端断开连接connect(clientSocket, &QTcpSocket::disconnected, this, [=]() {QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] 客户端下线!";ui->listWidget->addItem(log);// 释放clientSocket, 防止文件描述符泄漏// 非立即销毁, 而是通知Qt在下一个事件循环中销毁clientSocket->deleteLater();});
}QString Widget::process(const QString request)
{return request;
}

客户端

在这里插入图片描述

// widget.h#include <QWidget>
#include <QTcpSocket>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();private:Ui::Widget *ui;QTcpSocket* socket;
};// widget.cpp#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QMessageBox>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->setWindowTitle("客户端");socket = new QTcpSocket(this);// 和服务器建立连接// 这个函数非阻塞socket->connectToHost("127.0.0.1", 9090);connect(socket, &QTcpSocket::readyRead, this, [=]() {QString response = socket->readAll();ui->listWidget->addItem("服务器内容: " + response);});// 阻塞等待, 确认连接成功bool flag = socket->waitForConnected();if (!flag){QMessageBox::critical(this, "连接服务器失败", socket->errorString());exit(1);}
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{const QString& text = ui->lineEdit->text();// 发送数据给服务器socket->write(text.toUtf8());// 显示ui->listWidget->addItem("客户端内容: " + text);// 清空输入框ui->lineEdit->setText("");
}

3、HTTP客户端

Qt只提供HTTP客户端。核心API:QNetworkAccessManager , QNetworkRequest , QNetworkReply。

QNetworkAccessManager

在这里插入图片描述

发起HTTP GET和POST请求,皆返回QNetworkReply 对象。

QNetworkRequest表示一个HTTP请求协议,不包含body。如果需要发送一个带有 body 的请求(比如 post),会在 QNetworkAccessManager 的 post 方法中通过单独的参数来传入body。

在这里插入图片描述

QVariant是一个类型可变的值。

QNetworkRequest::KnownHeaders 是一个枚举类型,常用取值:

在这里插入图片描述
在这里插入图片描述

QNetworkReply 表示一个 HTTP 响应。这个类同时也是 QIODevice 的子类。

在这里插入图片描述

QNetworkReply 信号 finished 会在客户端收到完整的响应数据之后触发。

在这里插入图片描述
在这里插入图片描述

// widget.h#include <QWidget>
#include <QNetworkAccessManager>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();private:Ui::Widget *ui;QNetworkAccessManager* manager;
};// widget.cpp#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QNetworkReply>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->setWindowTitle("客户端");manager = new QNetworkAccessManager(this);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{// 获取输入框的urlQUrl url(ui->lineEdit->text());// 构造HTTP请求对象QNetworkRequest request(url);// 发送请求// 如果是post, 第二个参数就是body// get不阻塞, 因为它不负责等待响应QNetworkReply* response = manager->get(request);// 信号槽处理响应connect(response, &QNetworkReply::finished, this, [=]() {if(response->error() == QNetworkReply::NoError){QString html = response->readAll();ui->plainTextEdit->setPlainText(html);}elseui->plainTextEdit->setPlainText(response->errorString());response->deleteLater();});
}

4、音频

关于Qt的音视频,需要先引入multimedia多媒体模块才能正常运行。主要的类是QSound,只能播放.wav格式的音频文件

创建一个QWidget项目,使用qrc来引入音频文件

在这里插入图片描述

放一个按钮到界面上

// widget.h#include <QWidget>
#include <QSound>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();private:Ui::Widget *ui;QSound* sound;
};// widget.cpp#include <QDebug>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);sound = new QSound(":/audio.wav", this);
}void Widget::on_pushButton_clicked()
{sound->play();
}

结束。


http://www.ppmy.cn/server/164859.html

相关文章

第四章:玄丹-React商品管理实战

https://ant-design.antgroup.com/components/table-cn 在这里找到我们的 Table 表格,来完成我们的商品功能实战,下面我们会学到 表格类组件的渲染表格函数组件的渲染图片上传组件弹窗组件按钮组件axios 工具的封装分页功能的实现商品管理基础表格 import React from react;…

Immutable设计 SimpleDateFormat DateTimeFormatter

专栏系列文章地址&#xff1a;https://blog.csdn.net/qq_26437925/article/details/145290162 本文目标&#xff1a; 理解不可变设计模式&#xff0c;时间format有线程安全要求的注意使用DateTimeFormatter 目录 ImmutableSimpleDateFormat 非线程安全可以synchronized解决&a…

wire单总线通信

概述: 1-Wire技术由美国Dallas Semiconductor公司于1989年首次推出&#xff0c;最初的1-Wire标准主要用于便携数据传输模块&#xff0c;减少了设备之间的连接复杂性。 1-Wire单总线的核心特点 单线通信&#xff1a; 1-Wire协议通过一根信号线实现数据和时钟的双向传输&…

Linux网络 HTTPS 协议原理

概念 HTTPS 也是一个应用层协议&#xff0c;不过 是在 HTTP 协议的基础上引入了一个加密层。因为 HTTP的内容是明文传输的&#xff0c;明文数据会经过路由器、wifi 热点、通信服务运营商、代理服务器等多个物理节点&#xff0c;如果信息在传输过程中被劫持&#xff0c;传输的…

QT+mysql+python 效果:

# This Python file uses the following encoding: utf-8 import sysfrom PySide6.QtWidgets import QApplication, QWidget,QMessageBox from PySide6.QtGui import QStandardItemModel, QStandardItem # 导入需要的类# Important: # 你需要通过以下指令把 form.ui转为ui…

Prompt提示词完整案例:让chatGPT成为“书单推荐”的高手

大家好&#xff0c;我是老六哥&#xff0c;我正在共享使用AI提高工作效率的技巧。欢迎关注我&#xff0c;共同提高使用AI的技能&#xff0c;让AI成功你的个人助理。 许多人可能会跟老六哥一样&#xff0c;有过这样的体验&#xff1a;当我们遇到一个能力出众或对事物有独到见解的…

游戏引擎 Unity - Unity 设置为简体中文、Unity 创建项目

Unity Unity 首次发布于 2005 年&#xff0c;属于 Unity Technologies Unity 使用的开发技术有&#xff1a;C# Unity 的适用平台&#xff1a;PC、主机、移动设备、VR / AR、Web 等 Unity 的适用领域&#xff1a;开发中等画质中小型项目 Unity 适合初学者或需要快速上手的开…

Debezium Oracle Connector SCN处理优化指南

Debezium Oracle Connector SCN处理优化指南 📌 问题场景 SCN跳跃场景: 起始SCN:15,000(含数据变更)结束SCN:1,000,000(无中间数据)默认批次大小:10,000 → 需执行985次无效查询🚀 优化方案 1. 自适应批次调整 代码位置:LogMinerStreamingChangeEventSource.j…