【Qt初入江湖】Qt QNetworkAccessManager底层架构、原理详细描述

鱼弦:CSDN内容合伙人、CSDN新星导师、51CTO(Top红人+专家博主) 、github开源爱好者(go-zero源码二次开发、游戏后端架构 https://github.com/Peakchen)

    

QNetworkAccessManager是Qt网络模块中的一个类,它用于管理网络请求和响应。QNetworkAccessManager提供了一种简单的方式来发送HTTP请求并处理响应。它是基于事件驱动的架构,可以在后台线程中运行,以避免阻塞UI线程。

底层架构:

QNetworkAccessManager的底层架构是基于Qt的网络模块,它使用了多线程的架构来处理网络请求和响应。QNetworkAccessManager包含了多个子组件,其中最重要的是QNetworkReply和QNetworkRequest。QNetworkRequest负责管理HTTP请求,而QNetworkReply负责管理HTTP响应。

实现架构图:

+----------------+              +-------------------+
|                |              |                   |
|  QNetworkReply |<-------------| QNetworkAccessManager |
|                |              |                   |
+----------------+              +-------------------+
         |                                    |
         |                                    |
         |                                    |
         |                                    |
         |                                    |
+--------v-----------------------------+  +---v-------------------------+
|                                        |  |                             |
|                  Network               |  |         Socket              |
|                                        |  |                             |
+----------------------------------------+  +-----------------------------+

QNetworkAccessManager是Qt封装的一个网络请求管理器对象,它包含多个QNetworkReply对象,用于管理HTTP响应。在底层,QNetworkAccessManager使用Qt网络模块中的Socket对象来发送和接收网络请求和响应。

原理详细操作描述:

在Qt中使用QNetworkAccessManager非常简单。首先,我们需要创建一个QNetworkAccessManager对象,并使用它来发送HTTP请求。例如,以下代码演示了如何使用QNetworkAccessManager发送一个简单的HTTP GET请求:

QNetworkAccessManager* manager = new QNetworkAccessManager(this);
QNetworkReply* reply = manager->get(QNetworkRequest(QUrl("http://www.example.com")));

在上面的代码中,我们首先创建了一个QNetworkAccessManager对象,并使用get()函数来发送一个HTTP GET请求。get()函数接受一个QNetworkRequest对象作为参数,该对象指定了请求的URL和其他参数。get()函数返回一个QNetworkReply对象,该对象用于管理HTTP响应。

然后,我们可以使用QNetworkReply的函数来访问和操作HTTP响应。例如,以下代码演示了如何读取HTTP响应的内容:

QByteArray data = reply->readAll();

在上面的代码中,我们使用readAll()函数从QNetworkReply对象中读取HTTP响应的内容。

类中函数使用原理:

QNetworkAccessManager类中最重要的函数是get()、post()、put()和deleteResource(),它们分别用于发送HTTP GET、POST、PUT和DELETE请求。finished()是一个信号,用于在HTTP请求完成时发出通知。

下面是使用C++的Qt中QNetworkAccessManager类的一些常用函数的使用案例和详细介绍:

1. get()
该函数用于发送HTTP GET请求并获取响应。你可以使用QNetworkRequest设置请求的URL、头部信息等。

#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

// 创建QNetworkAccessManager对象
QNetworkAccessManager* manager = new QNetworkAccessManager();

// 创建QNetworkRequest对象并设置请求URL
QNetworkRequest request(QUrl("https://www.example.com"));

// 发送GET请求
QNetworkReply* reply = manager->get(request);

// 处理响应
connect(reply, &QNetworkReply::finished, [=]() {
    if (reply->error() == QNetworkReply::NoError) {
        QByteArray data = reply->readAll();
        // 处理响应数据
    } else {
        // 处理错误
    }
    
    // 清理资源
    reply->deleteLater();
});

2. post()
该函数用于发送HTTP POST请求并获取响应。你可以使用QNetworkRequest设置请求的URL、头部信息等,并使用QByteArray传递请求体数据。

#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

// 创建QNetworkAccessManager对象
QNetworkAccessManager* manager = new QNetworkAccessManager();

// 创建QNetworkRequest对象并设置请求URL
QNetworkRequest request(QUrl("https://www.example.com"));

// 设置请求头
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");

// 创建请求体数据
QByteArray postData;
postData.append("key1=value1&key2=value2");

// 发送POST请求
QNetworkReply* reply = manager->post(request, postData);

// 处理响应
connect(reply, &QNetworkReply::finished, [=]() {
    if (reply->error() == QNetworkReply::NoError) {
        QByteArray data = reply->readAll();
        // 处理响应数据
    } else {
        // 处理错误
    }
    
    // 清理资源
    reply->deleteLater();
});

3. head()
该函数用于发送HTTP HEAD请求并获取响应头信息。你可以使用QNetworkRequest设置请求的URL、头部信息等。

#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

// 创建QNetworkAccessManager对象
QNetworkAccessManager* manager = new QNetworkAccessManager();

// 创建QNetworkRequest对象并设置请求URL
QNetworkRequest request(QUrl("https://www.example.com"));

// 发送HEAD请求
QNetworkReply* reply = manager->head(request);

// 处理响应
connect(reply, &QNetworkReply::finished, [=]() {
    if (reply->error() == QNetworkReply::NoError) {
        QVariantMap headers = reply->rawHeaderPairs();
        // 处理响应头信息
    } else {
        // 处理错误
    }
    
    // 清理资源
    reply->deleteLater();
});

4. put()
该函数用于发送HTTP PUT请求并获取响应。你可以使用QNetworkRequest设置请求的URL、头部信息等,并使用QByteArray传递请求体数据。

#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

// 创建QNetworkAccessManager对象
QNetworkAccessManager* manager = new QNetworkAccessManager();

// 创建QNetworkRequest对象并设置请求URL
QNetworkRequest request(QUrl("https://www.example.com"));

// 设置请求头
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");

// 创建请求体数据
QByteArray putData;
putData.append("key1=value1&key2=value2");

// 发送PUT请求
QNetworkReply* reply = manager->put(request, putData);

// 处理响应
connect(reply, &QNetworkReply::finished, [=]() {
    if (reply->error() == QNetworkReply::NoError) {
        QByteArray data = reply->readAll();
        // 处理响应数据
    } else {
        // 处理错误
    }
    
    // 清理资源
    reply->deleteLater();
});

这些是使用C++的Qt中QNetworkAccessManager类的一些常用函数的使用案例和介绍。

以下是一个简单的实现示例:

#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);

    QNetworkAccessManager* manager = new QNetworkAccessManager();
    QNetworkReply* reply = manager->get(QNetworkRequest(QUrl("http://www.example.com")));

    QObject::connect(reply, SIGNAL(finished()), &app, SLOT(quit()));

    app.exec();

    QByteArray data = reply->readAll();
    qDebug() << data;

    return 0;
}

在上面的代码中,我们首先创建了一个QNetworkAccessManager对象,并使用get()函数发送了一个HTTP GET请求。然后,我们连接了reply对象的finished()信号到应用程序的quit()槽函数,以便在HTTP请求完成时退出应用程序。最后,我们使用readAll()函数从QNetworkReply对象中读取HTTP响应的内容。

一个在Web中使用QNetworkAccessManager的应用示例是通过HTTP协议下载文件。以下是一个简单的实现示例:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Download File</title>
</head>
<body>

    <form>
        <label for="url-input">URL:</label>
        <input id="url-input" type="text" name="url" value="https://www.example.com/file.pdf">
        <button id="download-button" type="button">Download</button>
    </form>

    <script>
        var button = document.getElementById("download-button");
        button.addEventListener("click", function() {
            var url = document.getElementById("url-input").value;
            var xhr = new XMLHttpRequest();
            xhr.open("GET", "/download?url=" + encodeURIComponent(url));
            xhr.responseType = "arraybuffer";
            xhr.onload = function() {
                if (this.status === 200) {
                    var blob = new Blob([this.response], {type: "application/pdf"});
                    var link = document.createElement("a");
                    link.href = URL.createObjectURL(blob);
                    link.download = "file.pdf";
                    link.click();
                } else {
                    alert("Download failed: " + this.statusText);
                }
            };
            xhr.send();
        });
    </script>

</body>
</html>

在上面的HTML代码中,我们创建了一个包含URL输入框和下载按钮的简单表单。当用户点击下载按钮时,我们使用XMLHttpRequest对象向服务器发送HTTP GET请求,并将URL作为查询参数传递。为了下载PDF文件,我们将响应的内容类型设置为“application/pdf”,并将响应转换为二进制数据。

在服务器端,我们可以使用Qt来处理HTTP请求,并使用QNetworkAccessManager来下载文件。以下是一个简单的实现示例:

#include <QCoreApplication>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <QtCore/QUrlQuery>
#include <QtCore/QFile>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>

void downloadFile(QNetworkAccessManager* manager, QUrl url, QString filename)
{
    QNetworkReply* reply = manager->get(QNetworkRequest(url));
    QObject::connect(reply, &QNetworkReply::finished, [reply, filename]() {
        if (reply->error() == QNetworkReply::NoError) {
            QFile file(QDir::temp().filePath(filename));
            if (file.open(QIODevice::WriteOnly)) {
                file.write(reply->readAll());
                file.close();
                qDebug() << "Downloaded file:" << file.fileName();
            } else {
                qWarning() << "Failed to write file:" << file.fileName() << "-" << file.errorString();
            }
        } else {
            qWarning() << "Download failed:" << reply->errorString();
        }
        reply->deleteLater();
    });
}

int main(int argc, char* argv[])
{
    QCoreApplication app(argc, argv);

    QNetworkAccessManager manager;
    QObject::connect(&manager, &QNetworkAccessManager::finished, &app, &QCoreApplication::quit);

    QUrlQuery query;
    query.setQuery(app.arguments().value(1));
    QString url = query.queryItemValue("url");

    if (!url.isEmpty()) {
        downloadFile(&manager, QUrl(url), "file.pdf");
    } else {
        qDebug() << "Usage:" << app.applicationName() << "url=<url>";
    }

    app.exec();

    return 0;
}

在上面的代码中,我们首先创建了一个QNetworkAccessManager对象,并连接了其finished()信号到应用程序的quit()槽函数,以便在下载完成后退出应用程序。然后,我们使用QUrlQuery对象解析URL查询参数,并使用QNetworkAccessManager对象下载文件。在下载完成后,我们将文件保存到临时目录,并输出文件名。

猜你喜欢

转载自blog.csdn.net/feng1790291543/article/details/131805121