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

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

一、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_OBJECT
 
public:
    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_OBJECT
 
public:
    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();
}

相关文章:

  • android lmkd.rc 介绍
  • 深度研究deep-research优秀开源项目
  • ABC 375
  • Android菜单栏
  • 网络爬虫-2:正则化
  • C#通过API接口返回流式响应内容---分块编码方式
  • 【计算机网络通信 AMQP】使用 Qt 调用 qamqp 库进行 AMQP 通信
  • DeepLabv3+改进11:在主干网络中添加CPCA注意力机制|聚焦于信息丰富的通道和重要区域
  • 基尔霍夫定律课后学习日志
  • 如何使用HACS一键集成米家与果家设备到HomeAssistant玩转智能家居
  • 【LInux】线程thread从内核原理到C++封装
  • Java泛型是什么?有什么作用?
  • 【一起来学kubernetes】8、k8s中的Ephemeral-Storage详解
  • 【QT:信号和槽】
  • MySQL(事物上)
  • RK3588 远程 SSH时出现WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
  • 二叉树的所有路径
  • 语音转文本SOTA模型部署的实战教程
  • Nginx 刷新后 404 的原因与解决方案
  • 通过特征值和特征向量实现的图像压缩和特征提取
  • 学者三年实地调查被判AI代笔,论文AI率检测如何避免“误伤”
  • 通往国际舞台之路:清政府与万国公会的交往
  • 蒋圣龙突遭伤病出战世预赛存疑,国足生死战后防线严重减员
  • 消息人士称泽连斯基已启程前往土耳其
  • 乌拉圭前总统何塞·穆希卡去世
  • 字母哥动了离开的心思,他和雄鹿队的缘分早就到了头