当前位置: 首页 > news >正文

Qt网络相关

“ 所有生而孤独的人,葆有的天真 ” 


         为了⽀持跨平台, QT对⽹络编程的 API 也进⾏了重新封装。本章会上手一套基于QT的网络通信编写

UDP Socket

        在使用Qt进行网络编程前,需要在Qt项目中的.pro文件里添加对应的网络模块( network ).

QT += core gui network

QUdpsocket 核心API

名称
类型
说明
原⽣ API
bind(const QHostAddress&, quint16)
方法
绑定指定的端⼝号
bind
receiveDatagram()
⽅法
返回 QNetworkDatagram . 读取 ⼀个 UDP 数据报.
recvfrom
writeDatagram(const
QNetworkDatagram&)
⽅法
发送⼀个 UDP 数据报.
sendto
readyRead
信号
在收到数据并准备就绪后触发
QNetworkDatagram(const
QByteArray&, const
QHostAddress& , quint16 )
构造函数
data()
⽅法
获取数据报内部持有的数据. 返回QByteArray
senderAddress()
⽅法
获取对端的 IP 地址.
senderPort()
⽅法
获取对端的端⼝号

基于udp的简单回显程序

· 服务端

🎃 创建界面,包含一个 QListWidget 用于显示消息

🎃 在主类中,创建QUdpSocket成员

 🎃 进行初始化

    // 1. 设置窗口标题this->setWindowTitle("服务器");// 2. 实例化socket = new QUdpSocket(this);// 3. 连接信号槽, 处理收到的请求connect(socket,&QUdpSocket::readyRead,this,&MainWindow::processRequest);// 4. 端口bind(ip,port)bool ret = socket->bind(QHostAddress::Any,9090);if(ret == false){QMessageBox::critical(nullptr,"服务器启动错误",socket->errorString());return;}

        一般来说,都是先建立信号与槽的连接,再进行网络端口的绑定。如果顺序反过来,当网络端口进行bind后,客户端就可以发送来消息处理,此时如果没来得及连接信号槽,为这个请求提供的服务就可能失效。

 🎃 槽函数实现(实现对端消息的回显功能)

QString MainWindow::process(const QString & req)
{return req;
}void MainWindow::processRequest()
{// 当走到这里 说明服务器已经收到对端信息递达的信号 触发的槽函数处理~// 1.获取请求const QNetworkDatagram& requestDatagram = socket->receiveDatagram();// QNetworkDatagram.data() 拿到对端请求的原始数据QString request = requestDatagram.data();// 2. 计算处理请求const QString& response = process(request);// 3.把响应写回到客⼾端QNetworkDatagram responseDatagram(response.toUtf8(),\requestDatagram.senderAddress(),requestDatagram.senderPort());socket->writeDatagram(responseDatagram);// 4.显示打印日志QString log = "[" + requestDatagram.senderAddress().toString() + ":"  +QString::number(requestDatagram.senderPort()) + "]" + " " + "req: " + request + " | " + "resp: " + response;ui->listWidget->addItem(log);
}

· 客户端

🧧 创建一个界面,包含用户发送消息窗口、发送按钮、输入栏。发送窗口仍然使用QListWidget,依次是pushButton、QLineEdit。

        先使⽤⽔平布局( layout) 把两个控件齐整。   

        进入到控件中的sizePolicy 设置为 “Expanding ”。 接着再使用垂直布局,将消息发送窗口与水平布局的两个空间再进行空间管理。当然我们需要在垂直布局中设置比例,否则比较难看~

        这样,简易的界面也算完成了。

🧧 初始化IP和端口

        在mainwindows.h中定义两个静态变量

static const QString& server_ip = "127.0.0.1";
static const quint16 server_port = 9090;
🧧 消息发送实现(槽函数) 
完成QUdpsocket实例化后,我们只需要关注数据报的发送即可。
void MainWindow::on_send_putton_clicked()
{// 1. 获取输入的内容const QString& text = ui->message_edit->text();// 2. 利用text构造数据报QNetworkDatagram requestDatagram = \QNetworkDatagram(text.toUtf8(),QHostAddress(server_ip),server_port);// 3.发送请求socket->writeDatagram(requestDatagram);// 4.前端回显ui->message_screen->addItem("客户端说: " + text);// 5.每发完一条消息 清空输入框ui->message_edit->clear();
}

🧧 接收客户端回显(槽函数) 

    // 接收服务端回显connect(socket,&QUdpSocket::readyRead,this,[=](){const QNetworkDatagram responseDatagram = socket->receiveDatagram();QString resp = responseDatagram.data();ui->message_screen->addItem(QString("服务器回显: " + resp));});

测试:
双方都能看到对端发送的消息,并能及时回显。

TCP Socket

        TCP相对于UDP而言要复杂很多,只要你曾学过网络知识。我们首先来了解了解Tcp Socket中的核心API。

QTcpServer 核心API

名称
类型
说明
对标原⽣ API
listen(const QHostAddress&,
quint16 port)
方法
绑定指定的地址和端⼝号, 并开始监听
bind 和 listen
nextPendingConnection()
方法
从系统中获取到⼀个已经建⽴好的 tcp 连接.
返回⼀个 QTcpSocket , 表⽰这个 客⼾端的连接.
accept
newConnection()
信号
有新的客⼾端建⽴连接好之后触发
readAll()
方法
读取当前接收缓冲区中的所有数据.  返回 QByteArray 对象
read
write(const QByteArray& )
方法
把数据写⼊ socket 中
write
readyRead
信号有数据到达并准备就绪时触发
deleteLater()
方法
暂时把 socket 对象标记为⽆效.
disconnected()
信号
连接断开时触发

        想对比于udp的核心API,我们会发现没有了于 "Datagram" 相关的任何接口了。这本质是因为TCP是面向字节流而非udp那样的数据报。

基于TCP的简单回显程序

        因为都是做回显,那么这里服务器、客户端的前端依旧同udp是一的 ~

· 服务端

🎨  编写QTcpServer

#include <QMainWindow>
#include <QString>
#include <QTcpServer>
#include <QHostAddress>
#include <QMessageBox>
#include <QTcpSocket>// 设置窗口信息this->setWindowTitle(" 服务器 ");// 1.实例化tcpserver = new QTcpServer(this);// 2.通过信号槽, 处理客⼾端建⽴的新连接.connect(tcpserver,&QTcpServer::newConnection,this,&MainWindow::processConnection);// 3.监听+bindbool ret = tcpserver->listen(QHostAddress::Any,9090);if(ret == false){QMessageBox::critical(nullptr,"服务器启动失败",tcpserver->errorString());exit(-1);}

🎨 继续修改 widget.cpp, 实现处理连接的具体⽅法processConnection

void MainWindow::processConnection()
{// 1.根据 listen 获取接收到的新连接// 注: 这里是 "QTcpSocket"QTcpSocket* clientsocket = tcpserver->nextPendingConnection();// 更新服务端日志QString log = QString("[") + clientsocket->peerAddress().toString() + ":" + \QString::number(clientsocket->peerPort()) + "] 客户端上线";ui->listWidget->addItem(log);    
}

🎨 完成回显工作(槽函数实现)

        可以发现,不管是做udp还是tcp的网络模型服务,我们都舍弃了用循环的方式处理请求。这会导致我们,一旦存在占用资源的连接不及时释放cpu资源,那么别的请求就不会被读取到,直到该请求的任务执行完成。

        Qt中的槽机制恰好避免了这样的困境,一旦发出信号,就执行槽函数即可~

    // 信号槽处理 处理收到请求的情况connect(clientsocket,&QTcpSocket::readyRead,this,[=](){// 字节流 把所有字节都 读上来const QString req = clientsocket->readAll();// 根据请求 制作响应const QString& resp = process(req);// 写回客户端clientsocket->write(resp.toUtf8());// 服务端回显QString log = "[" + clientsocket->peerAddress().toString() + ":" + QString::number(clientsocket->peerPort()) \+ "]" + " " + "req: " + req;ui->listWidget->addItem(log);});

        由于Tcp可靠性的特征,每一次客户端的连接都会被服务端保存着。当客户端断开连接时而服务端并不是释放两者之间用于连接的资源时,就会导致 资源泄漏~~

    // 通过信号槽, 处理断开连接的情况connect(clientsocket,&QTcpSocket::disconnected,this,[=](){QString log = QString("[") + clientsocket->peerAddress().toString() + ":" + \QString::number(clientsocket->peerPort()) + "] 客户端下线";ui->listWidget->addItem(log);// 释放资源clientsocket->deleteLater();    // 并不会立即释放});

· 客户端

👑 初始化mainwindow.cpp

    this->setWindowTitle("客户端");// 1. 实例化socketsocket = new QTcpSocket(this);// 2. 建立连接socket->connectToHost("127.0.0.1",9090);// 3.等待并确认连接是否出错bool ret = socket->waitForConnected();if(ret == false){QMessageBox::critical(nullptr,"连接失败",socket->errorString());exit(-1);}

👑 给按钮增加点击的 slot 函数, 实现发送请求给服务器      

void MainWindow::on_send_clicked()
{// 获得输入的内容 并输出在界面上const QString& text = ui->edit->text();ui->edit->clear();ui->messageScreen->addItem("已发送: " + text);// 真正的发送消息socket->write(text.toUtf8());
}
👑  通过信号槽, 处理收到的服务器的响应
    connect(socket,&QTcpSocket::readyRead,this,[=](){QString resp = socket->readAll();qDebug() << resp;ui->messageScreen->addItem("服务端回显: " + resp);});

测试:

        不管是响应还是,当客户端断开连接时,我们都能够完成对应的功能。

HTTP 

        进⾏ Qt 开发时, 和服务器之间的通信很多时候也会⽤到 HTTP 协议。我们大概需要以下几个步骤:

•   通过 HTTP 从服务器获取数据.
•   通过 HTTP 向服务器提交数据.

核心API

        关键类有三个 QNetworkAccessManager、QNetworkRequest、QNetworkReply .

🏀 QNetworkAccessManager 提供了 HTTP 的核⼼操作.
⽅法
说明
get(const QNetworkRequest& )
发起⼀个 HTTP GET 请求. 返回 QNetworkReply 对象.
post(const QNetworkRequest& , const
QByteArray& )
发起⼀个 HTTP POST 请求. 返回 QNetworkReply 对 象.

 

🏀 QNetworkRequest 表⽰⼀个 HTTP 请求.

如果需要发送⼀个带有 body 的请求(⽐如 post), 会在 QNetworkAccessManager 的 post ⽅法 中通过单独的参数来传⼊ body.
⽅法
说明
QNetworkRequest(const QUrl&)
通过 URL 构造⼀个 HTTP 请求.
setHeader(QNetworkRequest::KnownHeaders
header, const QVariant &value)
设置请求头.

🏀 QNetworkRequest::KnownHeaders 是⼀个枚举类型

⽅法
说明
ContentTypeHeader
描述 body 的类型
ContentLengthHeader
描述 body 的⻓度.
LocationHeader
⽤于重定向报⽂中指定重定向地址
CookieHeader
设置 cookie
UserAgentHeader
设置请求头.
🏀 QNetworkReply 表⽰⼀个 HTTP 响应:
⽅法
说明
error()
获取出错状态.
errorString()
获取出错原因的⽂本.
readAll()
读取响应 body
header(QNetworkRequest::KnownHeaders
header)
设置 cookie

构建一个Http客户端

        因为我们只需要构建一个模拟的HTTP请求。服务端则不需要我们进行什么编写~~ 

QPlainTextEdit vs QTextEdit

        QTextEdit会进⾏富 ⽂本解析, 如果得到的 HTTP 响应体积很⼤, 就会导致界⾯渲染缓慢甚⾄被卡住。

🏐 修改 mainwindow.h, 创建 QNetworkAccessManager 属性


#include <QMainWindow>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>QNetworkAccessManager* manager;

🏐 创建实例并初始化

    this->setWindowTitle(" Http请求发起器 ");// 1. 实例初始化manager = new QNetworkAccessManager(this);
🏐  编写按钮的 slot 函数, 实现发送 HTTP 请求功能.
void MainWindow::on_pushButton_clicked()
{// 1. 根据输入框里url,构造QurlQUrl url(ui->lineEdit->text());// 2. 构造http响应QNetworkRequest req(url);// 3. 以什么方法访问QNetworkReply* resp = manager->get(req);// 通过信号槽来处理响应connect(resp,&QNetworkReply::finished,this,[=](){if(resp->error() == QNetworkReply::NoError){QString html(resp->readAll());ui->plainTextEdit->setPlainText(html);}else{ui->plainTextEdit->setPlainText(resp->errorString());}resp->deleteLater();});
}
测试:


本篇到此结束,感谢你的阅读。

祝你好运,向阳而生~

相关文章:

Qt网络相关

“ 所有生而孤独的人&#xff0c;葆有的天真 ” 为了⽀持跨平台, QT对⽹络编程的 API 也进⾏了重新封装。本章会上手一套基于QT的网络通信编写。 UDP Socket 在使用Qt进行网络编程前&#xff0c;需要在Qt项目中的.pro文件里添加对应的网络模块( network ). QT core gui net…...

deepseek接入pycharm 进行AI编程

要将DeepSeek接入PyCharm进行AI编程,可以按照以下步骤操作: ### 1. 获取DeepSeek API访问权限 DeepSeek通常以API的形式对外提供服务,你需要在其官方网站注册账号,申请API访问权限。在申请通过后,会获得API密钥(API Key),这是后续调用API的关键凭证。 ### 2. 安装必要…...

Verilog基础(三):过程

过程(Procedures) - Always块 – 组合逻辑 (Always blocks – Combinational) 由于数字电路是由电线相连的逻辑门组成的&#xff0c;所以任何电路都可以表示为模块和赋值语句的某种组合. 然而&#xff0c;有时这不是描述电路最方便的方法. 两种always block是十分有用的&am…...

生成式AI安全最佳实践 - 抵御OWASP Top 10攻击 (上)

今天小李哥将开启全新的技术分享系列&#xff0c;为大家介绍生成式AI的安全解决方案设计方法和最佳实践。近年来&#xff0c;生成式 AI 安全市场正迅速发展。据 IDC 预测&#xff0c;到 2025 年全球 AI 安全解决方案市场规模将突破 200 亿美元&#xff0c;年复合增长率超过 30%…...

.Net WebAPI -[HttpPut(“{fileServiceId:int}“)]

[HttpPut("{fileServiceId:int}")] 这个写法是 ASP.NET Core 中的一个路由特性&#xff0c;用于定义一个 HTTP PUT 请求的路由&#xff0c;并指定路由参数的类型。 解析 HttpPut [HttpPut]&#xff1a; 这是一个 ASP.NET Core 的路由特性&#xff0c;用于标记一个方…...

[EAI-027] RDT-1B,目前最大的用于机器人双臂操作的机器人基础模型

Paper Card 论文标题&#xff1a;RDT-1B: a Diffusion Foundation Model for Bimanual Manipulation 论文作者&#xff1a;Songming Liu, Lingxuan Wu, Bangguo Li, Hengkai Tan, Huayu Chen, Zhengyi Wang, Ke Xu, Hang Su, Jun Zhu 论文链接&#xff1a;https://arxiv.org/ab…...

C基础寒假练习(7)

一、有 1、2、3、4个数字&#xff0c;能组成多少互不相同且无重复的三位&#xff1f; 都是多少&#xff1f; #include <stdio.h> int main() {// 定义数字数组int digits[] {1, 2, 3, 4};int n sizeof(digits) / sizeof(digits[0]);// 嵌套循环遍历所有排列for (int …...

Ajax:重塑Web交互体验的人性化探索

在数字化时代&#xff0c;网页的交互性和响应速度已成为衡量用户体验的关键指标。Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;&#xff0c;作为前端与后端沟通的桥梁&#xff0c;凭借其异步通信的能力&#xff0c;极大地提升了网页的动态性和用户友好度&…...

【DeepSeek背后的技术】系列二:大模型知识蒸馏(Knowledge Distillation)

目录 1 引言2 操作步骤和公式说明2.1 准备教师模型&#xff08;Teacher Model&#xff09;和学生模型&#xff08;Student Model&#xff09;2.2 生成软标签&#xff08;Soft Labels&#xff09;2.3 定义蒸馏损失函数2.4 训练学生模型2.5 调整超参数2.6 评估与部署 3 其他知识蒸…...

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.14 内存映射:处理超大型数组的终极方案

2.14 内存映射&#xff1a;处理超大型数组的终极方案 目录 #mermaid-svg-G91Kn9O4eN2k8xEo {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-G91Kn9O4eN2k8xEo .error-icon{fill:#552222;}#mermaid-svg-G91Kn9O4eN2k…...

【C++】STL——vector的使用

目录 &#x1f495;1.vector介绍 &#x1f495;2.vector的基本用法 &#x1f495;3.vector功能的具体用法 &#xff08;讲解&#xff09; &#x1f495;4.vector——size&#xff0c;capacity函数的使用 &#xff08;简单略讲&#xff09; &#x1f495;5.resize&#xff…...

springboot/ssm互联网智慧医院体检平台web健康体检管理系统Java代码编写

springboot/ssm互联网智慧医院体检平台web健康体检管理系统Java代码编写 基于springboot(可改ssm)vue项目 开发语言&#xff1a;Java 框架&#xff1a;springboot/可改ssm vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&am…...

介绍一下Mybatis的Executor执行器

Executor执行器是用来执行我们的具体的SQL操作的 有三种基本的Executor执行器&#xff1a; SimpleExecutor简单执行器 每执行一次update或select&#xff0c;就创建一个Statement对象&#xff0c;用完立刻关闭Statement对象 ReuseExecutor可重用执行器 可重复利用Statement…...

Wide Deep 模型:记忆能力与泛化能力

实验和完整代码 完整代码实现和jupyter运行&#xff1a;https://github.com/Myolive-Lin/RecSys--deep-learning-recommendation-system/tree/main 引言 Wide & Deep 模型是一种结合了线性模型&#xff08;Wide&#xff09;和深度神经网络&#xff08;Deep&#xff09;的混…...

Hot100之矩阵

73矩阵置零 题目 思路解析 收集0位置所在的行和列 然后该行全部初始化为0 该列全部初始化为0 代码 class Solution {public void setZeroes(int[][] matrix) {int m matrix.length;int n matrix[0].length;List<Integer> list1 new ArrayList<>();List<…...

Python语言的安全开发

Python语言的安全开发 引言 在信息技术迅速发展的今天&#xff0c;网络安全问题愈发凸显。随着Python语言的广泛应用&#xff0c;尤其是在数据分析、人工智能、Web开发等领域&#xff0c;其安全问题越来越受到重视。Python作为一门高效且易于学习的编程语言&#xff0c;虽然在…...

蓝桥杯刷题DAY3:Horner 法则 前缀和+差分数组 贪心

所谓刷题&#xff0c;最重要的就是细心 &#x1f4cc; 题目描述 在 X 进制 中&#xff0c;每一数位的进制不固定。例如&#xff1a; 最低位 采用 2 进制&#xff0c;第二位 采用 10 进制&#xff0c;第三位 采用 8 进制&#xff0c; 则 X 进制数 321 的十进制值为&#xff…...

java项目验证码登录

1.依赖 导入hutool工具包用于创建验证码 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.5.2</version></dependency> 2.测试 生成一个验证码图片&#xff08;生成的图片浏览器可…...

手写MVVM框架-环境搭建

项目使用 webpack 进行进行构建&#xff0c;初始化步骤如下: 1.创建npm项目执行npm init 一直下一步就行 2.安装webpack、webpack-cli、webpack-dev-server&#xff0c;html-webpack-plugin npm i -D webpack webpack-cli webpack-dev-server html-webpack-plugin 3.配置webpac…...

2025年2月2日(网络编程 tcp)

tcp 循环服务 import socketdef main():# 创建 socket# 绑定tcp_server socket.socket(socket.AF_INET, socket.SOCK_STREAM)tcp_server.bind(("", 8080))# socket 转变为被动tcp_server.listen(128)while True:# 产生专门为链接进来的客户端服务的 socketprint(&qu…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...