• C++ Qt 学习(六):Qt http 编程


    1. http 基础

    2. C++ Qt 用户登录、注册功能实现

    在这里插入图片描述

    • login_register.h
    #pragma once
    
    #include 
    #include "ui_login_register.h"
    #include 
    
    class login_register : public QDialog {
        Q_OBJECT
    
    public:
        login_register(QWidget *parent = Q_NULLPTR);
    
    private:
        void test_http_post();
        void test_timeout_http_post();
    
    private slots:
        void on_btnLogin_clicked();
        void post_requestFinished(QNetworkReply* reply);
    
    private:
        Ui::login_registerClass ui;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • login_register.cpp
    #pragma execution_character_set("utf-8")
    
    #include "login_register.h"
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    login_register::login_register(QWidget *parent) : QDialog(parent) {
        ui.setupUi(this);
    }
    
    void login_register::on_btnLogin_clicked() {
        //test_http_post();
        test_timeout_http_post();
    }
    
    void login_register::test_http_post() {
        QNetworkAccessManager* pHttpMgr = new QNetworkAccessManager();
    
        // 设置 url
        QString url = "http://127.0.0.1:8080/login";
    
        // 设置头信息
        QNetworkRequest requestInfo;
        requestInfo.setUrl(QUrl(url));
        requestInfo.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
    
        // setRawData
        QJsonObject rawJson;
        rawJson.insert("username", "zhangsan");
        rawJson.insert("password", "123456");
    
        QByteArray byte_array = QJsonDocument(rawJson).toJson();
      
        // 发送 post 请求
        QNetworkReply* reply = pHttpMgr->post(requestInfo, byte_array);
    
        if (reply) {
            // 添加事件循环机制,返回后再运行后面的
            connect(pHttpMgr, &QNetworkAccessManager::finished, 
                this, &login_register::post_requestFinished);
        }
    }
    
    void login_register::post_requestFinished(QNetworkReply* reply) {
        // 获取 http 状态码
        QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
        if (statusCode.isValid())
            qDebug() << "status code=" << statusCode.toInt();
    
        QVariant reason = reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
        if (reason.isValid())
            qDebug() << "reason=" << reason.toString();
    
        QNetworkReply::NetworkError err = reply->error();
    
        if (err != QNetworkReply::NoError) {
            // 请求失败
            QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
    
            QMessageBox::information(this, "warn",
                "http post failed, error code = " + statusCode.toString() + " error info: " + reply->errorString());
    
            return;
        } else {
            // 请求成功
            // 接收请求结果
            QByteArray responseByte = reply->readAll();
            QString strRes = responseByte;
    
            QMessageBox::information(this, "http post success",
                "post response = " + strRes);
        }
    }
    
    void login_register::test_timeout_http_post() {
        QNetworkAccessManager* pHttpMgr = new QNetworkAccessManager();
    
        // 设置 url
        QString url = "http://127.0.0.1:8080/login";
    
        // 设置头信息
        QNetworkRequest requestInfo;
        requestInfo.setUrl(QUrl(url));
        requestInfo.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
    
        // setRawData
        QJsonObject rawJson;
        rawJson.insert("username", "zhangsan");
        rawJson.insert("password", "123456");
    
        QByteArray byte_array = QJsonDocument(rawJson).toJson();
    
        // 发送 post 请求
        QNetworkReply* reply = pHttpMgr->post(requestInfo, byte_array);
    
        // 添加超时处理,1ms 超时
        QEventLoop eventloop;
        connect(reply, SIGNAL(finished()), &eventloop, SLOT(quit()));
    
        // 比如设置 1ms 内完成请求,否则就认为是超时
        QTimer::singleShot(1000, &eventloop, &QEventLoop::quit);
        eventloop.exec();
    
        QByteArray array;
        if (reply->isFinished()) {
            if (reply->error() == QNetworkReply::NoError) {
                // 正常结束,读取响应数据
                QByteArray result = reply->readAll();
                QString strRes = result;
    
                QMessageBox::information(this, "http post success",
                    "post response = " + strRes);
            } else {
                // 异常结束
                // 请求失败
                QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
    
                QMessageBox::information(this, "warn",
                    "http post failed, error code = " + statusCode.toString() + " error info: " + reply->errorString());
    
                return;
            }
        } else {
            // 请求超时
            disconnect(reply, &QNetworkReply::finished, &eventloop, &QEventLoop::quit);
            reply->abort();
            
            QMessageBox::information(this, "http post timeout", "http post timeout");
        }
    
        reply->deleteLater();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141

    3. Qt json 解析介绍

    • ch65_qtjson.cpp
    #include "ch65_qtjson.h"
    #include 
    #include  
    #include 
    #include 
    
    using namespace std;
    
    ch65_qtjson::ch65_qtjson(QWidget *parent) : QWidget(parent) {
        ui.setupUi(this);
    
        /*string json_str = R"(
            {
                "date": "20220701",
                "level": 1,
                "msg": "register account",
                "status": "success",
                "username": "jackli"
            }
        )";*/
    
        string json_str = R"({})";
    
        QString qstr = QString::fromStdString(json_str);
    
        if (qstr.isEmpty()) {
            qDebug() << "qstr is empty";
            return;
        }
    
        QByteArray jbyte = qstr.toLocal8Bit();
        // 捕获转换过程中出现的错误
        QJsonParseError error;
        QJsonDocument jdoc = QJsonDocument::fromJson(jbyte, &error);
    
        if (error.error != QJsonParseError::NoError) {
            // 有错误
            qDebug() << "json parse error";
            return;
        }
        qDebug() << "json parse success";
    
        if (jdoc.isNull() || jdoc.isEmpty()) {
            qDebug() << "json docment is empty";
            return;
        }
    
        QJsonObject jobj = jdoc.object();
        QString date = jobj["date"].toString();
        qDebug() << "date" << date;
    
        int level = jobj["level"].toInt();
        qDebug() << "level" << level;
    }
    
    ch65_qtjson::~ch65_qtjson() {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    4. C++ nlohmann::json 使用介绍

    • nlohmann::json

    • Qt 有 json 解析相关的类,但不推荐使用,建议使用 nlohmann::json,这个 json 适用于任何 C++ 框架

    • nlohmann::json 只需要一个头文件 json.hpp,不需要编译成 lib,直接放到项目中即可使用

    • main.cpp

    #include 
    #include "json.hpp"
    #include 
    
    using json_t = nlohmann::json;
    
    using namespace std;
    
    int parse_array() {
        string jsonstr = R"(
            {
                "id":"2022",
                "name":{"EnglishName":"JackMa"},
                "title":[
                    {
                        "company":"taobao", 
                        "position" : "AAA", 
                        "salary" : "10000"
                    },
                    { 
                        "company":"zhifubao",
                        "position" : "CCC",
                        "salary" : "890898" 
                    },
                    { 
                        "company":"pingtouge",
                        "position" : "KKK",
                        "salary" : "76843" 
                    }
                ]
            }
        )";
    
        try {
            json_t jsonObj = json_t::parse(jsonstr);
    
            // 取出 name
            json_t nameJson = jsonObj["name"];
            string engName = nameJson["EnglishName"];
            cout << "engName = " << engName << endl;
    
            // 取出 title
            json_t titleJson = jsonObj["title"];
            int size = titleJson.size();
            cout << "size = " << size << endl;
    
            for (auto jsonItem : titleJson) {
                cout << jsonItem["company"] << endl;
                cout << jsonItem["position"] << endl;
                cout << jsonItem["salary"] << endl;
            }
        } catch (const std::exception&) {
            return -1;
        }
    
        return 0;
    }
    
    int main() {
        /* 序列化,把 json 数据转成 string */
        json_t jRawdata;
        jRawdata["username"] = "jackli";
        jRawdata["pwd"] = "123456";
    
        // nlohmann::json 中的 dump 方法实现数据转储
        string _rawdata = jRawdata.dump(4);
        cout << _rawdata << endl; 
    
        /* 反序列化,把 string 数据转成 json */
        string json_str = R"(
            {
                "date": "20220701",
                "level": 1,
                "msg": "register account",
                "status": "success",
                "username": "jackli"
            }
        )";
    
        try  {
            json_t j2 = json_t::parse(json_str);
            string date = j2["date"];
            cout << date << endl;
        } catch (std::exception& e) {
            cout << "json parse failed" << endl;
            return -1;
        }
    
        /* 解析复杂 json 数据 */
        cout << "解析 json 数组" << endl;
        if (parse_array() != 0) {
            cout << "parse array failed" << endl;
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    5. libcurl 解析

    • libcurl 是一个跨平台的网络协议库,支持 http、https,ftp,telnet 等应用层协议
    • libcurl 主要功能就是用不同的协议连接和沟通不同的服务器

    5.1 libcurl 编译

    5.2 使用 libcurl 进行 http post 请求

    #include 
    #include "curl/curl.h"
    #include 
    #include 
    #include 
    #include "json.hpp"
    
    using namespace std;
    
    using json_t = nlohmann::json;
    
    // 数据处理回调函数
    size_t write_data(void* ptr, size_t size, size_t nmemb, void* stream) {
        string data((const char*)ptr, (size_t)size * nmemb);
        *((stringstream*)stream) << data << endl;
        return size * nmemb;
    }
    
    int main() {
        /* 以下代码为通过 Postman 生成 */
        // Postman 是一款用于发送 HTTP 请求的测试工具
        CURL* curl;
        CURLcode res;
        stringstream jsonRespon;
    
        curl = curl_easy_init();
        if (curl) {
            curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
            curl_easy_setopt(curl, CURLOPT_URL, "127.0.0.1:8080/login");
            curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
            //curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
            struct curl_slist* headers = NULL;
            headers = curl_slist_append(headers, "Content-Type: application/json");
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
            
            string data = R"(
                {
                    "username":"jackhui",
                    "password":"1234"
                }
            )";
    
            curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &jsonRespon);
    
            res = curl_easy_perform(curl);
            if (res != 0) {
                cout << "request failed" << endl;
                return -1;
            }
        }
        curl_easy_cleanup(curl);
        cout << "request success 222" << endl;
        /* 以上代码为通过 Postman 生成 */
    
        string json = jsonRespon.str();
    
        try {
            json_t j = json_t::parse(json);
            cout << j.dump(4) << endl;
    
            string data = j["date"];
        } catch (std::exception& e) {
            cout << "json parse failed" << endl;
            return -2;
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    在这里插入图片描述

    6. websocket

    6.1 基本概念

    • websocket 是 HTML5 中新增的一个协议,这个协议的出现,让客户端和服务器之前的数据交互变成全双工的

    • websocket 的出现,最主要的变化是允许服务器主动给客户端推送数据。这一大改变,就让 websocket 具有了以往其它协议无法比拟的实时通信能力。要实现 websocket 服务,需要客户端和服务端都得支持 websocket 协议才可以

    • websocket 详解

    • Websocket 能做什么?

      • 聊天、消息推送、多人在线业务
      • 推荐一个开源项目 OpenIM
    • websocket 与 http 的区别

      • 相同点
        • 都是一样基于 TCP 的,都是可靠性传输协议
        • 都是应用层协议
      • 不同点
        • websocket 是持久连接,http 是短连接
        • websocket 的协议是以 ws/wss 开头,http 对应的是 http/https
        • websocket 是有状态的,http 是无状态的
        • websocket 连接之后服务器和客户端可以双向发送数据,http 只能是客户端发起一次请求之后,服务器才能返回数据
        • websocket 连接建立之后,不需要再发送 request 请求,数据直接从 TCP 通道传输
    • websocketpp 是用 c++ 实现的一个 websocket 库,用来支持 websocket 协议

    6.2 C++ Qt 实现 websocket server

    Qt websocket 的实现(需包含 websockets 第三方模块)

    • QWebSocketServer(服务端)
    • QWebSocket(客户端)

    在这里插入图片描述

    • WebsocketServer.h
    #pragma once
    
    #include 
    #include "ui_WebsocketServer.h"
    #include 
    #include 
    #include 
    
    class WebsocketServerDemo : public QWidget {
        Q_OBJECT
    
    public:
        WebsocketServerDemo(QWidget *parent = Q_NULLPTR);
        ~WebsocketServerDemo();
    
    private slots:
        void on_btnOpenServer_clicked();
        void on_btnCloseServer_clicked();
        void on_btnSend_clicked();
    
        void onNewConnection();
        void processTextMessage(QString message);
        void socketDisconnected();
    
    private:
        Ui::WebsocketServerClass ui;
    
        QWebSocketServer* m_WebSocketServer = nullptr;
    
        QList<QWebSocket*> m_clients;
        bool m_debug;
        QWebSocket* pSocket;
        QDateTime* current_date_time;
        QMap<QString, QWebSocket*> mapSocket;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • WebsocketServer.cpp
    #include "WebsocketServer.h"
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    WebsocketServerDemo::WebsocketServerDemo(QWidget *parent) : QWidget(parent) {
        ui.setupUi(this);
       
        this->setWindowTitle(u8"Websocket Server");
        this->resize(1000, 600);
    
        ui.lineEdit_IP->setText("192.168.74.1");
        ui.lineEdit_Port->setText("8000");
    
        // 创建服务
        m_WebSocketServer = new QWebSocketServer(u8"server", QWebSocketServer::NonSecureMode);
    }
    
    WebsocketServerDemo::~WebsocketServerDemo() {
        if (m_WebSocketServer) {
            if(m_WebSocketServer->isListening())
                m_WebSocketServer->close();
        }  
    }
    
    // 开启服务
    void WebsocketServerDemo::on_btnOpenServer_clicked() {
        QString ip = ui.lineEdit_IP->text();
        QString port = ui.lineEdit_Port->text();
    
        // 监听 ip 和端口
        if (m_WebSocketServer->listen(QHostAddress(ip), port.toInt())) {
            ui.textEdit_RecvMsg->append(u8"服务开启成功");
            ui.btnOpenServer->setEnabled(false);
            // 服务成功开启则触发 onNewConnection() 槽函数
            connect(m_WebSocketServer, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
        } else {
            QMessageBox::information(this, u8"提示", u8"监听失败, 是否开启了代理,或者IP错误");
        }
    }
    
    // 关闭服务
    void WebsocketServerDemo::on_btnCloseServer_clicked() {
        if (m_WebSocketServer) {
            if (m_WebSocketServer->isListening()) {
                m_WebSocketServer->close();
                ui.btnOpenServer->setEnabled(true);
                ui.textEdit_RecvMsg->append(u8"服务关闭");
            }
        }
    }
    
    // 处理新的客户端连接
    void WebsocketServerDemo::onNewConnection() {
        pSocket = m_WebSocketServer->nextPendingConnection();
        m_clients << pSocket;
    
        // 处理接到消息的信号
        connect(pSocket, SIGNAL(textMessageReceived(QString)), this, SLOT(processTextMessage(QString)));
        // 处理断线的信号
        connect(pSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
    
        QString peerName = pSocket->requestUrl().toString();
        cout << "peerName = " << peerName.toStdString() << endl;
    
        // 将 ip 和 socket 保存到 map
        mapSocket[peerName] = pSocket;
    
        ui.listWidget_OnlineUser->addItem(peerName);
    }
    
    // 处理接收到的消息
    void WebsocketServerDemo::processTextMessage(QString message) {
        QString time = current_date_time->currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz ddd");
        QString item = pSocket->requestUrl().toString();
        ui.textEdit_RecvMsg->append(time + "" + item + "\n" + message);
    
        // 处理消息转发
        //...
    }
    
    // 客户端连接断开的操作
    void WebsocketServerDemo::socketDisconnected() {
        for (auto sk : m_clients) {
            if (!sk->isValid()) {
                QString temp_key;
                ui.textEdit_RecvMsg->append("map size = " + QString(mapSocket.size()) + "\n");
                for (auto it = mapSocket.begin(); it!=mapSocket.end(); it++) {
                    if (it.value() == sk) {
                        // 删除项
                        QList<QListWidgetItem*> list;
                        list = ui.listWidget_OnlineUser-> findItems(it.key(), Qt::MatchCaseSensitive);
    
                        QListWidgetItem* sel = list[0];
                        int r = ui.listWidget_OnlineUser->row(sel);
    
                        QListWidgetItem* item = ui.listWidget_OnlineUser->takeItem(r);
                        ui.listWidget_OnlineUser->removeItemWidget(item);
    
                        delete item;
                        m_clients.removeOne(sk);
    
                        QString time = current_date_time->currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz ddd");
                        ui.textEdit_RecvMsg->append(time + "" + it.key() + "下线了\n");
    
                        temp_key = it.key();
                    }
                }
    
                mapSocket.remove(temp_key);
                ui.textEdit_RecvMsg->append("after remove, map size = " + QString(mapSocket.size()) + "\n");
            }
        }
    }
    
    // 群发消息
    void WebsocketServerDemo::on_btnSend_clicked() {
        QString msg = ui.textEdit_send->document()->toPlainText();
    
        for (auto sk : m_clients) {
            sk->sendTextMessage(msg);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126

    6.3 C++ Qt 实现 websocket client

    在这里插入图片描述

    • WebSocketClientDemo.h
    #pragma once
    
    #include 
    #include "ui_WebSocketClientDemo.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    class WebSocketClientDemo : public QWidget {
        Q_OBJECT
    
    public:
        WebSocketClientDemo(QWidget *parent = Q_NULLPTR);
        ~WebSocketClientDemo();
    
    private slots:
        void on_btnConnect_clicked();
        void on_btnDisconnect_clicked();
        void on_btnSend_clicked();
    
        void onconnected();
        void onTextMessageReceived(const QString& message);
        void closeConnection();    
    
    private:
        Ui::WebSocketClientDemoClass ui;
    
        QUrl m_url;
        QWebSocket m_websocket;
        bool m_debug;
        QDateTime* current_date_time;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • WebSocketClientDemo.cpp
    #include "WebSocketClientDemo.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    WebSocketClientDemo::WebSocketClientDemo(QWidget *parent) : QWidget(parent) {
        ui.setupUi(this);
    
        ui.lineEdit_URL->setText("ws://192.168.74.1:8000/topic=10001");
        ui.label_ConnectStatus->clear();
    
        connect(&m_websocket, SIGNAL(connected()), this, SLOT(onconnected()));
        connect(&m_websocket, SIGNAL(disconnected()), this, SLOT(closeConnection()));
        connect(&m_websocket, SIGNAL(textMessageReceived(QString)), this, SLOT(onTextMessageReceived(QString)));
    }
    
    WebSocketClientDemo::~WebSocketClientDemo() {
        m_websocket.errorString();
        m_websocket.close();
    }
    
    // 断开连接操作
    void WebSocketClientDemo::closeConnection()  {   
        ui.label_ConnectStatus->setText("disconnected");
    }
    
    // 连接服务器
    void WebSocketClientDemo::on_btnConnect_clicked() {
        QString _text = ui.lineEdit_URL->text();
        QUrl url = QUrl(_text);
        m_websocket.open(url);
    }
    
    // 连接上之后
    void WebSocketClientDemo::onconnected() {
        ui.label_ConnectStatus->setText(tr("connected"));
        ui.btnConnect->setEnabled(false);
        ui.btnDisconnect->setEnabled(true);
    }
    
    // 收到消息
    void WebSocketClientDemo::onTextMessageReceived(const QString& message) {
        QString time = current_date_time->currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz ddd");
        ui.textEdit_recv->setText(time + "\n" + message);
    }
    
    // 断开
    void WebSocketClientDemo::on_btnDisconnect_clicked() {
        m_websocket.close();
    }
    
    // 发送消息
    void WebSocketClientDemo::on_btnSend_clicked() {
        QString msg = ui.textEdit_send->document()->toPlainText();
    
        string dataMsg = R"(
            "sender":"10002",
            "receiver":"10001",
            "msg":"你好"
        )";
        
        m_websocket.sendTextMessage(msg);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
  • 相关阅读:
    C语言内存函数
    基于时延估计的扰动卡尔曼滤波器外力估计
    产品经理进阶:外包原因及类型(一)
    香橙派Zero3安装miniconda3(问题多多,已全部解决)
    热点探测技术架构设计与实践
    三线表的制作
    Android使用Glide类加载服务器中的图片
    站在巨人肩上!阿里内部流传的Kubernetes实战手册,让你事半功倍
    RHCE---Linux的计划任务
    Bootstrap学习(十一)
  • 原文地址:https://blog.csdn.net/qq_42994487/article/details/134365427