QT编程之HTTP服务端与客户端技术

server/2025/3/19 0:28:24/

一、HTTP 服务器实现方案

  1. QtWebApp 集成

    • 将QtWebApp源码的 httpserver 目录导入项目,并在 .pro 文件中添加 include ($$PWD/httpserver/httpserver.pri)‌。
    • 配置 WebApp.ini 文件定义服务参数(IP、端口、线程池等),通过 HttpListener 类启动监听‌。
    • 自定义 RequestMapper 类处理不同 URL 路径的请求,继承 HttpRequestHandler 实现业务逻辑‌。
    • 详细使用方法参考:QtWebApp - wuyuan2011woaini - 博客园
  2. 原生 Qt 网络模块

    • 使用 QTcpServer 监听端口,通过 incomingConnection() 接收客户端连接‌。
    • 解析 HTTP 请求头(如 QByteArray 处理报文),动态生成响应内容(如 HTML/JSON)‌。

二、HTTP 客户端实现方案

Qt中的QNetworkAccessManager是网络请求管理的核心类,用于异步处理HTTP/HTTPS等协议通信。以下是其关键特性及使用方式:

1. ‌核心功能
  • 单例管理‌:整个Qt应用只需一个实例即可管理所有网络请求,负责维护代理、缓存等全局配置‌。
  • 请求调度‌:支持GET、POST、PUT、DELETE等标准HTTP方法,并通过队列管理并发请求(如HTTP协议默认同一主机/端口允许6个并发请求)‌。
 2. ‌基本使用步骤
// 创建实例
QNetworkAccessManager *manager = new QNetworkAccessManager(this);// 发送GET请求示例
connect(manager, &QNetworkAccessManager::finished, this, [=](QNetworkReply *reply) {// 处理响应数据QByteArray data = reply->readAll();reply->deleteLater(); // 避免内存泄漏
});
manager->get(QNetworkRequest(QUrl("http://example.com")));

通过finished信号接收响应,使用QNetworkReply对象解析返回数据和元信息(如HTTP头)‌。

QNetworkAccessManager manager;  
QUrl url("http://example.com/api/resource");  
QNetworkRequest request(url);  // 添加鉴权信息(与 GET 请求相同)  
QByteArray authHeaderData = "Basic " + yourBase64EncodedAuthString;  
request.setRawHeader(QByteArray("Authorization"), authHeaderData);  // 准备 POST 数据(这里只是一个简单的示例)  
QByteArray postData = "key1=value1&key2=value2";  // 发送 POST 请求  
QNetworkReply *reply = manager.post(request, postData);
3. ‌异步处理与资源管理
  • 异步API‌:所有请求非阻塞主线程,通过信号槽机制通知完成状态‌。
  • 资源释放‌:需手动调用reply->deleteLater()释放QNetworkReply对象,不可在槽函数中直接delete‌。
4. ‌高级配置
  • 代理与缓存‌:可通过setProxy()setCache()方法设置全局代理及缓存策略‌。
  • SSL加密连接‌:使用connectToHostEncrypted()建立HTTPS连接,支持自定义SSL配置‌。
5. ‌错误处理

监听errorOccurred信号处理网络错误:

connect(reply, &QNetworkReply::errorOccurred, [](QNetworkReply::NetworkError code) {qDebug() << "Error:" << code;
})‌;
6. ‌超时控制

通过QTimer实现异步请求超时机制:

QTimer::singleShot(5000, ‌:ml-search[reply] {  // 5秒超时if (reply && reply->isRunning()) {reply->abort();qDebug() << "Request timeout";}
})‌;
 7. ‌鉴权处理

在请求头中添加鉴权信息(如Authorization):

QNetworkRequest request;
request.setRawHeader("Authorization", "Bearer token123");
manager->get(request)‌:ml-citation{ref="3" data="citationList"}。
 8. ‌设置请求头

如果你需要设置请求头(例如,设置Content-Typeapplication/json):

request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

 8. ‌同步阻塞网络请求

QEventLoop在接收网络返回内容结束之前,一直阻塞等待。

#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QEventLoop>
#include <QDebug>struct TestA {int data; // 示例数据// 其他字段
};class NetworkManager : public QObject {Q_OBJECTpublic:NetworkManager(QObject* parent = nullptr) : QObject(parent) {manager = new QNetworkAccessManager(this);}TestA getTestA() {QEventLoop loop;TestA result;// 发起网络请求QNetworkRequest request(QUrl("http://www.example.com"));QNetworkReply* reply = manager->get(request);// 连接槽函数解析数据connect(reply, &QNetworkReply::finished, [&]() {if (reply->error() == QNetworkReply::NoError) {QByteArray response = reply->readAll();result = parseResponse(response);} else {qWarning() << "Network error:" << reply->errorString();}reply->deleteLater();loop.quit();});// 阻塞等待网络请求完成loop.exec();return result;}private:QNetworkAccessManager* manager;TestA parseResponse(const QByteArray& response) {TestA parsedData;// 假设解析为整数数据parsedData.data = QString(response).toInt();return parsedData;}
};
#include <QCoreApplication>int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);NetworkManager networkManager;TestA data = networkManager.getTestA();qDebug() << "Received data:" << data.data;return a.exec();
}
 9. ‌异步非阻塞网络请求

通过设置回调函数,将网络请求应答回调出去。

#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QDebug>
#include <functional>struct TestA {int data; // 示例数据// 其他字段
};class NetworkManager : public QObject {Q_OBJECTpublic:using Callback = std::function<void(const TestA&)>;NetworkManager(QObject* parent = nullptr) : QObject(parent) {manager = new QNetworkAccessManager(this);}void getTestA(const Callback& callback) {// 发起网络请求QNetworkRequest request(QUrl("http://www.example.com"));QNetworkReply* reply = manager->get(request);// 连接槽函数解析数据connect(reply, &QNetworkReply::finished, this, [this, reply, callback]() {TestA result;if (reply->error() == QNetworkReply::NoError) {QByteArray response = reply->readAll();result = parseResponse(response);} else {qWarning() << "Network error:" << reply->errorString();}reply->deleteLater();callback(result);});}private:QNetworkAccessManager* manager;TestA parseResponse(const QByteArray& response) {TestA parsedData;// 假设解析为整数数据parsedData.data = QString(response).toInt();return parsedData;}
};
#include <QCoreApplication>void handleResult(const TestA& data) {qDebug() << "Received data:" << data.data;QCoreApplication::quit();
}int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);NetworkManager networkManager;networkManager.getTestA(handleResult);return a.exec();
}

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

相关文章

Spring Cloud Stream - 构建高可靠消息驱动与事件溯源架构

一、引言 在分布式系统中&#xff0c;传统的 REST 调用模式往往导致耦合&#xff0c;难以满足高并发和异步解耦的需求。消息驱动架构&#xff08;EDA, Event-Driven Architecture&#xff09;通过异步通信、事件溯源等模式&#xff0c;提高了系统的扩展性与可观测性。 作为 S…

C++ primer plus 类和对象下

目录 前言 一 this指针 二 对象数组 三 类作用域 总结 前言 接着上一篇继续 一 this指针 我们可能看到这个this指针是不知道干什么的&#xff0c;但是我们可以通过一个问题来引入这个&#xff0c;就比如我们上一章的程序&#xff0c;我们知道是用来计算股票的&#xf…

前端(vue)学习笔记(CLASS 4):组件组成部分与通信

1、组件的三大组成部分&#xff08;结构/样式/逻辑&#xff09; 注意点&#xff1a; 1、结构只能有一个根元素 2、全局样式&#xff08;默认&#xff09;&#xff0c;影响所有组件&#xff1b;局部样式&#xff0c;scoped下样式&#xff0c;只作用于当前组件 3、el根实例独…

平板作为笔记本副屏使用spacedesk

平板作为笔记本的一块副屏使用 软件 spacedesk 已上传&#xff0c;可自行下载。&#xff08;上传需要审核且只能绑定一个资源&#xff0c;可在官网自行下载&#xff0c;或私聊我&#xff09; PC版 移动版 spacedesk-2-1-17.apk 电脑版按照提示一步一步安装节即可移动端直接…

SpringBoot入门-(1) Maven【概念+流程】

SpringBoot入门-(1) Maven 动机 对于企业级大项目而言&#xff0c;需要手动导入很大Jar包&#xff0c;费时费力&#xff0c;且Jar包之间也可能存在依赖和冲突&#xff0c;这些关系导致Jar包之间想毛线团一样缠在一起&#xff0c;因此我们需要一个包管理系统帮我们自动下载导入…

06.Python基础4

目录 元组 tuple 1.概述 2.可变数据为什么可变 3.不可变数据如何变化 4.基础操作 4.1创建元组 4.2定位元素 4.3遍历元组 4.4序列拆包 5.字符串 str 5.1定义 5.2编码 5.2.1字符集 5.2.2编码方式 5.2.3不可变 5.3序列 5.4字面值 5.4.1单引和双引号的区别 5.4.2…

jmeter 循环控制器遍历列表中的数据

jmeter遍历列表中的数据并使用if控制器做相应的处理 测试场景请求获取列表接口发送请求JSON Extractor 提取对应字段 Loop Controller计数器If Controller 测试场景 请求获取列表接口使用循环控制器遍历接口&#xff0c;根据state字段判断是否发起其他请求 请求获取列表接口 …

vue/react/vite前端项目打包的时候加上时间最简单版本,防止后端扯皮

如果你是vite项目&#xff0c;直接写一个vite的插件&#xff0c;通过这个插件可以动态注入环境变量&#xff0c;然后当打包的时候&#xff0c;自动注入这个时间到环境变量中&#xff0c;然后在项目中App.vue中或者Main.tsx中打印出来&#xff0c;这就知道是什么时候编译的项目了…