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

使用 Qt GRPC 构建高效的 Trojan-Go 客户端:详细指南

  • 使用 Qt GRPC 构建高效的 Trojan-Go 客户端:详细指南
    • 初识 Qt 和 gRPC
      • 什么是 Qt?
      • 什么是 gRPC?
    • 项目结构概述
    • 创建 proto 文件定义 API
      • 下载 api.proto 文件
      • 解析 proto 文件
        • 1. packageoption 语句
        • 2. 消息类型定义
          • Traffic
          • Speed
          • User
          • UserStatus
          • GetTrafficRequestGetTrafficResponse
          • ListUsersRequestListUsersResponse
          • GetUsersRequestGetUsersResponse
          • SetUsersRequestSetUsersResponse
        • 3. 服务定义
          • TrojanClientService
          • TrojanServerService
    • 配置 CMake 构建系统
      • CMake 配置解析
    • 实现 Trojan-Go 客户端
      • main.cpp 内容
      • 代码详解
      • 使用定时器实现数据流量和速度监控
    • 总结

在这里插入图片描述
trojan-go client
在这里插入图片描述

使用 Qt GRPC 构建高效的 Trojan-Go 客户端:详细指南

在上一篇 使用gRPC C++创建动态库以获取Trojan-go客户端的流量和速度信息 文章中使用纯 C++,这次随着 qt6.8 lts 发布,Qt GRPC 作为稳定模块推出,借此机会使用 Qt GRPC 实现该功能。

初识 Qt 和 gRPC

什么是 Qt?

Qt 是一个跨平台的 C++ 框架,用于开发图形界面和非图形界面应用。它提供了丰富的库支持、良好的跨平台兼容性、自动化的信号槽机制,使得在大型应用程序中管理事件和响应更为便捷。在本文中,Qt 提供了自动化工具来简化 Protobuf 和 gRPC 的代码生成,并结合 Qt 的 gRPC 模块,使得构建 gRPC 客户端更加便捷。

什么是 gRPC?

gRPC 是一种高性能的 RPC 框架,由 Google 开发,用于实现不同语言之间的服务调用。其基于 HTTP/2 协议,利用 Protocol Buffers(Protobuf)作为接口描述语言来定义服务和数据结构,允许客户端和服务器之间的轻量化通信。gRPC 的优势在于它的跨平台支持、灵活性和良好的性能,广泛应用于微服务架构和物联网领域。


项目结构概述

在创建项目之前,我们先来定义项目的目录结构,以确保文件结构清晰、便于管理:

trojan-go
├── api.proto          # Protobuf 文件,用于定义 gRPC 服务和消息格式
├── CMakeLists.txt     # CMake 构建文件,配置了编译选项、依赖项
└── main.cpp           # 主程序文件,实现客户端功能
  • api.proto:包含 API 的 gRPC 服务定义和数据结构。
  • CMakeLists.txt:配置 CMake 构建系统。
  • main.cpp:实现了 Trojan-Go 客户端的主要逻辑。

强制依赖 protoc.exe ,需要添加到环境变量中,从 https://github.com/protocolbuffers/protobuf/releases/download/v28.3/protoc-28.3-win64.zip 下载。


创建 proto 文件定义 API

proto 文件定义了客户端与服务器之间的通信规则。我们将在 api.proto 文件中定义数据结构和 gRPC 服务接口,确保客户端和服务器之间能够准确传递数据。

下载 api.proto 文件

下载 trojan-go api.proto 文件,文件内容如下:

syntax = "proto3";

package trojan.api;
option go_package = "github.com/p4gefau1t/trojan-go/api/service";

message Traffic {
    uint64 upload_traffic = 1;
    uint64 download_traffic = 2;
}

message Speed {
    uint64 upload_speed = 1;
    uint64 download_speed = 2;
}

message User {
    string password = 1;
    string hash = 2;
}

message UserStatus {
    User user = 1;
    Traffic traffic_total = 2;
    Speed speed_current = 3;
    Speed speed_limit = 4;
    int32 ip_current = 5;
    int32 ip_limit = 6;
}

message GetTrafficRequest {
    User user = 1;
}

message GetTrafficResponse {
    bool success = 1;
    string info = 2;
    Traffic traffic_total = 3;
    Speed speed_current = 4;
}

message ListUsersRequest {

}

message ListUsersResponse {
    UserStatus status = 1;
}

message GetUsersRequest {
    User user = 1;
}

message GetUsersResponse {
    bool success = 1;
    string info = 2;
    UserStatus status = 3;
}

message SetUsersRequest {
    enum Operation {
        Add = 0;
        Delete = 1;
        Modify = 2;
    }
    UserStatus status = 1;
    Operation operation = 2;
}

message SetUsersResponse {
    bool success = 1;
    string info = 2;
}

service TrojanClientService {
    rpc GetTraffic(GetTrafficRequest) returns(GetTrafficResponse){}
}

service TrojanServerService {
    // list all users
    rpc ListUsers(ListUsersRequest) returns(stream ListUsersResponse){}
    // obtain specified user's info
    rpc GetUsers(stream GetUsersRequest) returns(stream GetUsersResponse){}
    // setup existing users' config
    rpc SetUsers(stream SetUsersRequest) returns(stream SetUsersResponse){}
}
解析 proto 文件

这个 api.proto 文件定义了用于 Trojan API 的 gRPC 服务和消息结构,描述了客户端与服务器之间的通信模式。以下是该文件的详细解释:

1. packageoption 语句
package trojan.api;
option go_package = "github.com/p4gefau1t/trojan-go/api/service";
  • package 声明了 proto 文件的包名,trojan.api 用于在生成的代码中作为命名空间。
  • option go_package 定义了用于 Go 语言生成代码的包名,便于 Go 项目中导入。
2. 消息类型定义
Traffic
message Traffic {
    uint64 upload_traffic = 1;
    uint64 download_traffic = 2;
}
  • Traffic 消息定义了用户的上传和下载流量,字段类型为 uint64 表示无符号 64 位整数,适合表示较大的流量数据。
Speed
message Speed {
    uint64 upload_speed = 1;
    uint64 download_speed = 2;
}
  • Speed 消息记录了上传和下载速度,同样使用 uint64 类型来表示。
User
message User {
    string password = 1;
    string hash = 2;
}
  • User 消息包含用户的密码和哈希值,用于用户身份验证或标识。
UserStatus
message UserStatus {
    User user = 1;
    Traffic traffic_total = 2;
    Speed speed_current = 3;
    Speed speed_limit = 4;
    int32 ip_current = 5;
    int32 ip_limit = 6;
}
  • UserStatus 消息表示用户的状态信息,包含用户数据 (User)、总流量 (Traffic)、当前和限制速度 (Speed)、当前和限制的 IP 数量。
GetTrafficRequestGetTrafficResponse
message GetTrafficRequest {
    User user = 1;
}

message GetTrafficResponse {
    bool success = 1;
    string info = 2;
    Traffic traffic_total = 3;
    Speed speed_current = 4;
}
  • GetTrafficRequest 包含 User 数据,用于请求流量信息。
  • GetTrafficResponse 返回请求状态 success、信息 info,以及流量数据和速度数据。
ListUsersRequestListUsersResponse
message ListUsersRequest {}

message ListUsersResponse {
    UserStatus status = 1;
}
  • ListUsersRequest 不含字段,用于请求用户列表。
  • ListUsersResponse 返回每个用户的状态信息。
GetUsersRequestGetUsersResponse
message GetUsersRequest {
    User user = 1;
}

message GetUsersResponse {
    bool success = 1;
    string info = 2;
    UserStatus status = 3;
}
  • GetUsersRequest 请求特定用户的信息。
  • GetUsersResponse 返回状态 success、信息 info 和用户状态 UserStatus
SetUsersRequestSetUsersResponse
message SetUsersRequest {
    enum Operation {
        Add = 0;
        Delete = 1;
        Modify = 2;
    }
    UserStatus status = 1;
    Operation operation = 2;
}

message SetUsersResponse {
    bool success = 1;
    string info = 2;
}
  • SetUsersRequest 包含 UserStatusOperation,用于增加、删除或修改用户。
  • SetUsersResponse 返回操作状态 success 和相关信息 info
3. 服务定义
TrojanClientService
service TrojanClientService {
    rpc GetTraffic(GetTrafficRequest) returns(GetTrafficResponse){}
}
  • 定义 GetTraffic RPC 方法,允许客户端请求其流量信息。
TrojanServerService
service TrojanServerService {
    // list all users
    rpc ListUsers(ListUsersRequest) returns(stream ListUsersResponse){}
    // obtain specified user's info
    rpc GetUsers(stream GetUsersRequest) returns(stream GetUsersResponse){}
    // setup existing users' config
    rpc SetUsers(stream SetUsersRequest) returns(stream SetUsersResponse){}
}
  • TrojanServerService 包含 3 个方法:
    • ListUsers:返回用户列表,使用数据流式响应。
    • GetUsers:获取特定用户信息,支持流式请求和响应。
    • SetUsers:修改用户信息,通过流式请求和响应实现。

这个 api.proto 文件定义了 Trojan API 的服务与数据结构,支持流量查询、用户信息获取、用户列表和配置管理等功能。


配置 CMake 构建系统

接下来在 CMakeLists.txt 文件中配置 CMake,以便编译和链接所需的库和依赖。

cmake_minimum_required(VERSION 3.16)
project(trojan-go LANGUAGES CXX)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Protobuf Grpc)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Protobuf Grpc)

add_executable(client main.cpp)

qt_add_protobuf(client
    PROTO_FILES
        api.proto
)

qt_add_grpc(client CLIENT
    PROTO_FILES
        api.proto
)

include(GNUInstallDirs)
install(TARGETS client
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
CMake 配置解析
  • qt_add_protobufqt_add_grpc 用于生成 Protobuf 和 gRPC 的 C++ 代码。
  • install 指定安装路径,将可执行文件安装到系统的标准目录。

实现 Trojan-Go 客户端

main.cpp 文件实现了客户端的主要逻辑,负责与服务器通信并处理流量信息。

main.cpp 内容
#include <QCoreApplication>
#include <QTimer>
#include <memory>
#include "api.qpb.h"
#include "api_client.grpc.qpb.h"
#include <QGrpcHttp2Channel>
#include <QGrpcChannelOptions>
#include <QGrpcStatus>
#include <QGrpcCallReply>

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

    trojan::api::TrojanClientService::Client client;

    QGrpcChannelOptions channelOptions;
    QUrl clientApi = QUrl("http://127.0.0.128:10000"/*用户设定的 trojan-go api 地址和端口*/, QUrl::StrictMode);
    std::shared_ptr<QGrpcHttp2Channel> channel = std::make_shared<QGrpcHttp2Channel>(clientApi, channelOptions);

    if(client.attachChannel(channel)) {
        qDebug() << "attachChannel success";
    } else {
        qDebug() << "attachChannel failed";
    };

    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, &a, [&]() {
        trojan::api::User user;
        user.setPassword("trojan-go.com"/*用户连接服务器的密码*/);
        trojan::api::GetTrafficRequest req;
        req.setUser(user);

        std::unique_ptr<QGrpcCallReply> reply = client.GetTraffic(req);
        auto *replyPtr = reply.get();
        QObject::connect(
          replyPtr,
          &QGrpcCallReply::finished,
          &a,
          [reply = std::move(reply)](const QGrpcStatus &status) {
              if(!status.isOk()) {
                  qDebug() << "Failed to send message: " << status;
              } else {
                  trojan::api::GetTrafficResponse response;
                  if(reply->read(&response)) {
                      qDebug() << "Success:" << response.success();
                      qDebug() << "Info:" << response.info();
                      double downloadTrafficMB = response.trafficTotal().downloadTraffic() / 1024.0 / 1024.0;
                      double uploadTrafficMB   = response.trafficTotal().uploadTraffic() / 1024.0 / 1024.0;
                      double downloadSpeedMBps = response.speedCurrent().downloadSpeed() / 1024.0 / 1024.0;
                      double uploadSpeedMBps   = response.speedCurrent().uploadSpeed() / 1024.0 / 1024.0;

                      qDebug() << QString("Download Traffic: %1 MB").arg(downloadTrafficMB, 0, 'f', 2);
                      qDebug() << QString("Upload Traffic: %1 MB").arg(uploadTrafficMB, 0, 'f', 2);
                      qDebug() << QString("Download Speed: %1 MB/s").arg(downloadSpeedMBps, 0, 'f', 2);
                      qDebug() << QString("Upload Speed: %1 MB/s").arg(uploadSpeedMBps, 0, 'f', 2);
                      qDebug() << "";
                  } else {
                      qDebug() << "Failed to parse GetTrafficResponse.";
                  }
              }
          },
          Qt::SingleShotConnection);
    });

    timer.start(500);
    return a.exec();
}
代码详解
  • 连接服务器:使用 QGrpcHttp2Channel 通过 HTTP/2 连接到服务器。
  • 定时器监控:每 500 毫秒发送一次 GetTraffic 请求以获取最新流量和速度统计数据。
  • 结果解析和输出:解析服务器返回的流量数据并输出到控制台。
使用定时器实现数据流量和速度监控

通过 Qt 的 QTimer 实现客户端定时请求服务器流量和速度统计数据并进行处理。在实际应用中,定时更新数据可以实时监控服务器的状态,有助于及时获取连接信息并检测异常。


总结

本文介绍了如何使用 Qt 和 gRPC 实现一个高效的 Trojan-Go 客户端。从环境配置、Protobuf 文件定义、CMake 构建配置到主程序逻辑,我们全面讲解了客户端实现的每一步骤。借助 Qt 和 gRPC 的自动化工具,开发者能够更高效地实现客户端应用,同时享受 gRPC 高效的通信和 Qt 的跨平台支持。这一项目展示了 gRPC 的强大应用场景,也为开发更复杂的网络应用打下了基础。


http://www.kler.cn/a/375103.html

相关文章:

  • 微服务实战系列之玩转Docker(十六)
  • 补齐:相交链表:扣160
  • 安装fpm,解决*.deb=> *.rpm
  • o1驾驶无人机后空翻,OpenAI开发者日惊掉下巴!2分钟爆改代码写App
  • Spring Boot 配置文件详解与最佳实践
  • 微服务实战系列之玩转Docker(十七)
  • 抽丝剥茧 分布式服务框架设计 实战落地篇
  • Spring AOP(定义、使用场景、用法、3种事务、事务失效场景及解决办法、面试题)
  • Spring beanFactoryPostProcessor
  • Redis 线程控制 问题
  • 在linux中是如何运行一个应用程序的?
  • (七)JavaWeb后端开发1——Maven
  • 大语言模型驱动的跨域属性级情感分析——论文阅读笔记
  • 创造tips的秘籍——PHP回调后门
  • Redis 实战 问题
  • 【Sublime Text】格式化Json和XML
  • 线代的几何意义(一)——向量,坐标,矩阵
  • thinkphp和vue基于Workerman搭建Websocket服务实现用户实时聊天,完整前后端源码demo及数据表sql
  • Docker部署jenkins容器时,允许jenkins容器内部控制宿主机上的docker
  • 正向解析,反向解析
  • CSS3新增长度单位(二)
  • 从比亚迪超越特斯拉,看颠覆全球市场的中国力量
  • 大语言模型微调方法详解【全量微调、PEFT、LoRA、Adapter】
  • Rust 力扣 - 2090. 半径为 k 的子数组平均值
  • 低压电容补偿不用时会有电流损耗吗?
  • Lampiao靶机入侵实战