Qt 网络编程:远程过程调用(RPC)与 WebSocket 实时通信

person ~白~日~梦~~    watch_later 2024-12-23 15:28:42
visibility 50    class RPC,WebSocket    bookmark 专栏

远程过程调用(RPC)和 WebSocket 是现代网络编程中常用的技术,广泛应用于分布式系统、实时通信和 API 集成等领域。Qt 提供了强大的网络支持,包括 WebSocket 客户端、JSON-RPC 协议的实现以及与 REST API 的集成。本文将深入探讨这些技术,并结合代码示例详细讲解如何使用 Qt 实现远程过程调用、WebSocket 实时通信以及与 REST API 的交互。

一、远程过程调用(RPC)

远程过程调用(RPC)是一种协议,它允许程序在一台计算机上调用另一台计算机上的函数或方法,就像调用本地函数一样。RPC 协议通常用于客户端与服务器之间的通信。

1.1 JSON-RPC 协议的实现

JSON-RPC 是一种轻量级的远程过程调用(RPC)协议,它使用 JSON 格式来编码数据,并通过 HTTP、WebSocket 等协议传输。Qt 本身没有提供对 JSON-RPC 的直接支持,但我们可以通过 Qt 的 JSON 支持和网络模块轻松实现这一协议。

示例代码:JSON-RPC 请求与响应

假设我们有一个服务器实现,它支持接收 JSON-RPC 请求并返回响应。客户端通过发送 JSON 格式的请求来调用远程函数。

1.1.1 客户端代码
#include <QCoreApplication>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QDebug>

class RpcClient : public QObject {
    Q_OBJECT

public:
    RpcClient(QObject *parent = nullptr) : QObject(parent) {
        manager = new QNetworkAccessManager(this);
        connect(manager, &QNetworkAccessManager::finished, this, &RpcClient::onFinished);
    }

    void sendRequest() {
        // 构建 JSON-RPC 请求
        QJsonObject json;
        json["jsonrpc"] = "2.0";
        json["method"] = "add";
        json["params"] = QJsonArray{5, 3};
        json["id"] = 1;

        QJsonDocument doc(json);
        QByteArray requestData = doc.toJson();

        // 发送 HTTP 请求
        QNetworkRequest request(QUrl("http://localhost:8080/rpc"));
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

        manager->post(request, requestData);
    }

private slots:
    void onFinished(QNetworkReply *reply) {
        if (reply->error() == QNetworkReply::NoError) {
            QByteArray response = reply->readAll();
            QJsonDocument doc = QJsonDocument::fromJson(response);
            QJsonObject jsonResponse = doc.object();
            qDebug() << "RPC Response:" << jsonResponse["result"].toInt();
        } else {
            qDebug() << "Error:" << reply->errorString();
        }
        reply->deleteLater();
    }

private:
    QNetworkAccessManager *manager;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    RpcClient client;
    client.sendRequest();
    return a.exec();
}

#include "main.moc"
1.1.2 服务器端代码(简单实现)

服务器端会解析客户端请求,执行相应的方法,并返回结果。

#include <QCoreApplication>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QHttpServer>
#include <QHttpServerRequest>
#include <QHttpServerResponse>
#include <QDebug>

class RpcServer : public QObject {
    Q_OBJECT

public:
    RpcServer(QObject *parent = nullptr) : QObject(parent) {
        server = new QHttpServer(this);
        connect(server, &QHttpServer::newRequest, this, &RpcServer::handleRequest);
        server->listen(QHostAddress::Any, 8080);
    }

private slots:
    void handleRequest(const QHttpServerRequest &request, const QHttpServerResponse &response) {
        // 解析 JSON-RPC 请求
        QJsonDocument doc = QJsonDocument::fromJson(request.body());
        QJsonObject jsonRequest = doc.object();

        if (jsonRequest["method"] == "add") {
            // 执行方法
            QJsonArray params = jsonRequest["params"].toArray();
            int result = params[0].toInt() + params[1].toInt();

            // 构建响应
            QJsonObject jsonResponse;
            jsonResponse["jsonrpc"] = "2.0";
            jsonResponse["result"] = result;
            jsonResponse["id"] = jsonRequest["id"];

            QJsonDocument responseDoc(jsonResponse);
            response.setBody(responseDoc.toJson());
            response.setStatusCode(200);
        } else {
            response.setStatusCode(404);
            response.setBody("Method not found");
        }
    }

private:
    QHttpServer *server;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    RpcServer server;
    return a.exec();
}

#include "main.moc"

1.2 使用 JSON-RPC 协议的应用场景

JSON-RPC 协议适用于以下场景:

  • 客户端与服务器交互:如 Web 应用、桌面应用与远程服务之间的通信。
  • 分布式系统:微服务之间的调用。
  • 第三方服务集成:如调用外部 API,进行数据交换。

二、WebSocket 实时通信

WebSocket 是一种用于客户端和服务器之间进行全双工通信的协议,广泛应用于实时应用(如在线聊天、股票行情、多人游戏等)。Qt 支持 WebSocket 客户端和服务器端的实现。

2.1 使用 WebSocket 实现实时通信

示例代码:WebSocket 客户端

#include <QCoreApplication>
#include <QWebSocket>
#include <QDebug>

class WebSocketClient : public QObject {
    Q_OBJECT

public:
    WebSocketClient(QObject *parent = nullptr) : QObject(parent) {
        socket = new QWebSocket;
        connect(socket, &QWebSocket::connected, this, &WebSocketClient::onConnected);
        connect(socket, &QWebSocket::disconnected, this, &WebSocketClient::onDisconnected);
        connect(socket, &QWebSocket::textMessageReceived, this, &WebSocketClient::onMessageReceived);
    }

    void connectToServer() {
        socket->open(QUrl("ws://localhost:1234"));
    }

    void sendMessage(const QString &message) {
        socket->sendTextMessage(message);
    }

private slots:
    void onConnected() {
        qDebug() << "Connected to WebSocket server";
        sendMessage("Hello WebSocket server");
    }

    void onDisconnected() {
        qDebug() << "Disconnected from WebSocket server";
    }

    void onMessageReceived(const QString &message) {
        qDebug() << "Received message:" << message;
    }

private:
    QWebSocket *socket;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    WebSocketClient client;
    client.connectToServer();
    return a.exec();
}

#include "main.moc"

示例代码:WebSocket 服务器

#include <QCoreApplication>
#include <QWebSocketServer>
#include <QWebSocket>
#include <QDebug>

class WebSocketServer : public QObject {
    Q_OBJECT

public:
    WebSocketServer(QObject *parent = nullptr) : QObject(parent) {
        server = new QWebSocketServer(QStringLiteral("Echo Server"), QWebSocketServer::NonSecureMode, this);
        connect(server, &QWebSocketServer::newConnection, this, &WebSocketServer::onNewConnection);
        server->listen(QHostAddress::Any, 1234);
    }

private slots:
    void onNewConnection() {
        QWebSocket *socket = server->nextPendingConnection();
        connect(socket, &QWebSocket::textMessageReceived, this, &WebSocketServer::onMessageReceived);
        connect(socket, &QWebSocket::disconnected, this, &WebSocketServer::onDisconnected);
    }

    void onMessageReceived(const QString &message) {
        qDebug() << "Received message:" << message;
        QWebSocket *socket = qobject_cast<QWebSocket *>(sender());
        if (socket) {
            socket->sendTextMessage("Echo: " + message);
        }
    }

    void onDisconnected() {
        QWebSocket *socket = qobject_cast<QWebSocket *>(sender());
        if (socket) {
            socket->deleteLater();
        }
    }

private:
    QWebSocketServer *server;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    WebSocketServer server;
    return a.exec();
}

#include "main.moc"

2.2 使用 WebSocket 的应用场景

WebSocket 协议特别适用于以下场景:

  • 实时消息推送:如聊天应用、股票实时行情。
  • 在线多人游戏:在游戏服务器和客户端之间进行即时数据交换。
  • 协作平台:如多人在线协作、白板等应用场景。

三、与 REST API 的交

互(QNetworkAccessManager)

在现代应用中,很多 Web 服务都是基于 REST 构建的。Qt 提供了 QNetworkAccessManager 类,用于处理 HTTP 请求和响应,使得与 REST API 的交互变得简单。

3.1 使用 QNetworkAccessManager 调用 REST API

示例代码:调用 REST API

#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDebug>

class RestClient : public QObject {
    Q_OBJECT

public:
    RestClient(QObject *parent = nullptr) : QObject(parent) {
        manager = new QNetworkAccessManager(this);
        connect(manager, &QNetworkAccessManager::finished, this, &RestClient::onFinished);
    }

    void makeRequest() {
        // 设置 REST API 请求的 URL
        QNetworkRequest request(QUrl("https://jsonplaceholder.typicode.com/posts"));
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

        // 发起 GET 请求
        manager->get(request);
    }

private slots:
    void onFinished(QNetworkReply *reply) {
        if (reply->error() == QNetworkReply::NoError) {
            QByteArray response = reply->readAll();
            qDebug() << "Response:" << response;
        } else {
            qDebug() << "Error:" << reply->errorString();
        }
        reply->deleteLater();
    }

private:
    QNetworkAccessManager *manager;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    RestClient client;
    client.makeRequest();
    return a.exec();
}

#include "main.moc"

3.2 使用 REST API 的应用场景

REST API 适用于以下场景:

  • Web 服务调用:与第三方服务或系统进行交互。
  • 跨平台应用:通过 HTTP 请求与不同平台的服务通信。
  • 数据交换:通过标准化接口在应用之间交换数据。

四、总结

通过本文的讲解,我们学习了如何使用 Qt 实现远程过程调用(RPC)、WebSocket 实时通信以及与 REST API 的交互。每种技术都有其独特的优势和应用场景,可以根据具体需求灵活选择。Qt 提供了强大的网络编程功能,使得网络通信变得更加高效和易于实现。希望通过这些代码示例,你能够在自己的项目中熟练运用这些技术,提升应用的网络通信能力。

评论区
评论列表
menu