IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> QNetworkAccessManager 和 libcurl 网络接口 -> 正文阅读

[网络协议]QNetworkAccessManager 和 libcurl 网络接口

Qt 提供了 QNetworkAccessManager 及其相关的类,方便用户编写网络接口,但向较旧的库搭建的服务器 post 时,发现在服务器端只接收到 header,body 丢失了。推测是为了安全性,Qt 或者目前比较新的库采用这个机制 —— 将 header 与 body 拆开发送。但 Qt 似乎不兼容旧协议中 header 与 body 一并发送的机制,于是改为调用 libcurl 的网络接口。记录一下使用 Qt 的 API 和 libcurl 的 API 已经调通的 https get/post 请求,两者均能正常向 postman 搭建的模拟服务器发送请求,但只有 libcurl 的接口能向 iqims 发送请求。

QNetworkAccessManager

get

QByteArray QiqimsClient::getData(QString url)
{
    QByteArray retRespon;
    QNetworkAccessManager manager;
    QNetworkRequest request;

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

    QSslConfiguration config = QSslConfiguration::defaultConfiguration();
    config.setProtocol(QSsl::TlsV1_2);
    config.setPeerVerifyMode(QSslSocket::VerifyNone);
    request.setSslConfiguration(config);

    QNetworkReply* reply = manager.get(request);
    QEventLoop eventLoop;
    connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
    eventLoop.exec();
    if (reply->error() != QNetworkReply::NoError) {
        sigShowRespon(reply->errorString());
    }
    else {
        retRespon = reply->readAll();
    }
    delete reply;
    return retRespon;
}

post

bool QiqimsClient::QNetWorkPost(QString url, QByteArray postData)
{
    QNetworkRequest request;
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json;charset=utf-8");
//    request.setRawHeader("Accept", "*/*");
//    request.setRawHeader("Expect", "100-continue");
//    request.setRawHeader("Connection", "Keep-Alive");
//    request.setHeader(QNetworkRequest::ContentLengthHeader, postData.length());
//    request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);

    request.setUrl(url);
    // skip ssl
    QSslConfiguration sslConf;
    sslConf.setProtocol(QSsl::TlsV1_2);
    sslConf.setPeerVerifyMode(QSslSocket::VerifyNone);
    request.setSslConfiguration(sslConf);

    // post
//    qDebug() << "send:" << oneItemObj;
    QNetworkAccessManager *manager = new QNetworkAccessManager(this);
    QNetworkReply *reply = manager->post(request, postData);

    // waite reply
    QEventLoop eventLoop;
    QTimer timer;
    timer.setInterval(5000);    // set 5s timeout
    timer.setSingleShot(true);
    connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);
    connect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit);
    timer.start();
    eventLoop.exec();

    if(timer.isActive()) {
        timer.stop();
    } else {
        disconnect(manager, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit);
        reply->abort();
        qDebug() << "https request timeout";
        return false;
    }

    int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

    if(reply->error() != QNetworkReply::NoError) {
        emit sigShowRespon(QString("Code:%1").QString::number(statusCode));
        emit sigShowRespon(QString("Err:%1").arg(reply->errorString()));
        reply->deleteLater();
        return false;
    } else {
        int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
        emit sigShowRespon(QString("Code:%1").QString::number(statusCode));
        // server reply normal
        if(statusCode == 200) {     
            QByteArray replyContent = reply->readAll(); 
            emit sigShowRespon(replyContent);
            return true;
        } else {
            reply->deleteLater();
            return false;
        }
    }
    return true;
}

libcurl

libcurl 主要通过 SSL(Secure Sockets Layer 安全套接层)和 TLS(Transport Layer Security 传输层安全),在传输层对网络连接进行加密。

在 Qt 中引入 curl 库

电脑上安装了 VS2015 或者其他版本可以自己编译。

  1. https://curl.se/download.html 官网下载 curl 包。
  2. 在命令行窗口设置 VS 的环境变量,只会在当前 CMD 生效。
 "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\vcvars32.bat"
  1. 到 curl\winbuild 目录下编译
"cd D:\curl-7.85.0\winbuild
  1. 编译
nmake /f Makefile.vc mode=dll VC=12

在这里插入图片描述
编译出来的库在 D:\curl-7.85.0\builds\libcurl-vc12-x86-release-dll-ipv6-sspi-schannel,测试一下
在这里插入图片描述

–insecure 表示跳过证书验证,编译成功,可以访问 https。

  1. 把 libcurl-vc12-x86-release-dll-ipv6-sspi-schannel 文件夹改个简单的名字 curl,放到工程目录中,在 .pro 工程文件中添加路径。
INCLUDEPATH += ./libcurl/include/curl
LIBS += -L$$PWD/libcurl/lib/ -llibcurl
  1. 包含头文件
#include "libcurl/include/curl/curl.h"
  1. 把 libcurl/bin/libcurl.dll 复制到编译出来的 .exe 同一目录下

get

QString IqimsService::curlGet(QString url)
{
    //https
    QString responeData;
    CURL *curl;
    CURLcode res;
    curl_global_init(CURL_GLOBAL_DEFAULT);
    curl = curl_easy_init();
    if(curl) {
        // set url, change QString to char* beacuse use c++ lib
        char* setUrl;
        QByteArray urlBa = url.toLatin1();
        setUrl = urlBa.data();
        curl_easy_setopt(curl, CURLOPT_URL, setUrl);
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
        //set timeout, (s)
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);

        // set a call back function to get response
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, getUrlResponse);
        // responeData is the 4th param in getUrlResponse, save respone data to it
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&responeData);

        // skip ssl
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
        // Perform the request, res will get the return code
        res = curl_easy_perform(curl);  // waite request here

        // Check for errors
        if(res != CURLE_OK) {
            qDebug() << "curl_easy_strerror:" << curl_easy_strerror(res);
        }
        curl_easy_cleanup(curl);
    }
    curl_global_cleanup();
    return responeData;
}

post

QString IqimsService::curlPost(QString url, QByteArray postData)
{
    //https
    QString responeData;
    CURL *curl;
    CURLcode res;
    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    if(curl) {
        curl_slist *http_headers = NULL;
        http_headers = curl_slist_append(http_headers, "Accept: application/json");
        http_headers = curl_slist_append(http_headers, "Content-Type: application/json");//text/html
        http_headers = curl_slist_append(http_headers, "charsets: utf-8");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, http_headers);

        //set method to post
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");

        // set url, change QString to char* beacuse use c++ lib
        char* setUrl;
        QByteArray urlBa = url.toLatin1();
        setUrl = urlBa.data();
        curl_easy_setopt(curl, CURLOPT_URL, setUrl);

        //set timeout, (s)
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 3);

        // show debug message
        // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

        // set post Data, change QByteArray to char* beacuse use c++ lib
        char* setPostData;
        setPostData = postData.data();
        curl_easy_setopt(curl,CURLOPT_POSTFIELDS, setPostData);

        // set a call back function to get response
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, getUrlResponse);

        // responeData is the 4th param in getUrlResponse, save respone data to it
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&responeData);

        // skip ssl
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);

        // Perform the request, res will get the return code
        res = curl_easy_perform(curl);  // waite request here

        // Check for errors
        if(res != CURLE_OK) {
            qDebug() << curl_easy_strerror(res);
        }
        curl_easy_cleanup(curl);
    }
    curl_global_cleanup();
    return responeData;
}
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-09-15 02:20:34  更:2022-09-15 02:21:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:42:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码