Thrift C++

发布时间 2023-12-28 16:34:54作者: 有梦-

一、引子

Thrift is an interface definition language and binary communication protocol that is used to define and create services for numerous languages.

Thrift是用于...(使用接口定义语言和二进制通信协议定义并创建跨语言服务) 的框架,允许开发者在不同的编程语言之间通信。

二、安装(OS: ubuntu18.04/ubuntu20.04/ubuntu22.04; Thrift: 0.20.0)

0. 更新包管理器

sudo apt update

1. 安装依赖

sudo apt install -y build-essential automake bison flex pkg-config libboost-all-dev linssl-dev

  1) bison: Bison(GNU Bison)是一个用于生成解析器的工具。

  2) flex:Flex(Fast Lexical Analyzer Generator)是一个用于生成词法分析器的工具。

  3) libboost-all-dev:是 Boost C++ 库的开发包,包含了 Boost 库的所有开发文件和头文件。

  4) libssl-dev:是 OpenSSL 库的开发包,它包含了 OpenSSL 库的头文件和用于开发的其他文件。

  其余依赖较为常见。

2. 获取下载源码

wget http://apache.mirror.gtcomm.net/thrift/0.15.0/thrift-0.15.0.tar.gz

3. 解压缩文件

tar -xvzf thrift-0.15.0.tar.gz

4. 进入目录,配置并构建

cd thrift-0.20.0
./configure
make

5. 安装Thrift

sudo make install

三、案例

1. 开发流程

  1)按照需求编写thrift接口定义文件

  2)利用thrift binary为不同的语言生成代码

  3)根据需求,修改生成的代码(Server端代码),以编写实际的业务逻辑

  4)编写客户端代码,编译,集成。

2. rpc

  1)创建目录并创建ping.thrift

mkdir thrift_ping
cd thrift_ping
touch ping.thrift

  2)编写ping.thrift,其内容如下所示:

# ping.thrift

/**
 * Thrift files can namespace, package, or prefix their output in various
 * target languages
 */

namespace cpp pingtest

/**
 * Defining a class named pinger
 */

service pinger {
    /**
     * client calls ping method to make sure service process is active or dead
     */
    void ping()
}

  3)生成服务器端模板代码

thrift --gen cpp -o . ping.thrift

  主要服务器端的模板代码并不涉及业务,因此需要自己按需编写server端代码(仅作演示可用gen-cpp/pinger_server.skeleton.cpp)。

  4)编译server端可执行文件

cp gen-cpp/* .
g++ -g -Wall -std=c++11 -I/usr/local/include -L/usr/local/lib ./*.cpp -o server -lthrift

  5)编写客户端 client.cpp ,其内容如下所示:

#include <iostream>

#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>

#include "pinger.h"

using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

using namespace pingtest;

int main() {
    std::shared_ptr<TTransport> socket(new TSocket("localhost", 9090));
    std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
    std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
    pingerClient client(protocol);

    try {
        transport->open();

        client.ping();

        transport->close();
    } catch (TException& tx) {
        std::cout << "ERROR: " << tx.what() << std::endl;
    }

    return 0;
}

  6)编译客户端代码

g++ -g -Wall -std=c++11 client.cpp pinger.cpp -o client -lthrift

  7)打开两个终端界面

    1--运行服务器端,打开监听端口

./server

    2--运行客户端,每运行一次,服务器端打印一遍"ping"

./client

  **可自行尝试在两台服务器上运行上述代码,主要修改服务器端口中TSocket的地址信息为服务器的地址信息(IP地址),前提:两台设备可以相互ping通。**

3. 数据传输--与rpc差不多,不过有传递数据而已。

可参考以下博客(抱歉这里的拿来主义,偷点懒,若遇到环境问题,可留言)

技术: Thrift | 梅林日志 (wizardmerlin.github.io)

四、架构

 从下往上依次是(有不同意见可指出来,十分欢迎):

  1. 传输层

    实际的数据传输发生在传输层。Thrift 提供了多种传输层协议,例如 TSocket、TFramedTransport、TBufferedTransport 等,用于在客户端和服务端之间传输数据。

  2. 协议层

    协议层定义了数据的序列化和反序列化规则,使得不同语言和平台之间可以有效地交换数据。Thrift 支持多种协议,包括 TBinaryProtocol、TJSONProtocol、TCompactProtocol 等。

  3. 数据结构层

    结构体、异常和集合:在Thrift中,可以定义结构体、集合和异常等数据结构。这些数据结构用于在服务器之间传输数据,且支持嵌套结构。

  4. 服务层

    Thrift服务:定义了在客户端和服务器之间远程调用的服务接口。通过 IDL 文件定义的服务接口在编译过程中生成对应的客户端和服务器代码,使得不同语言的应用能够通过这些服务进行通信。

  5. 编译器层

    Thrift编译器:IDL文件需要经过Thrift层处理。Thrift编译器将IDL文件转换为不同编程语言的代码,生成用于序列化和反序列化数据以及调用远程服务的代码。

  6. IDL(Interface Definition Layer)层

    IDL文件:首先定义了接口层的规范,这是通过使用IDL文件完成的。IDL文件描述了要在不同语言之间传输的数据结构和服务接口。

五、详细说明

  1. Thrift支持的数据结构

    1)基本数据类型

    •   bool: 布尔类型,取值为 truefalse
    •   byte: 8 位带符号整数。
    •   i16: 16 位带符号整数。
    •   i32: 32 位带符号整数。
    •   i64: 64 位带符号整数。
    •   double: 双精度浮点数。
    •   string: 字符串。

    2)结构体:结构体是一种用户定义的数据结构,可以包含多个字段。每个字段都有自己的类型和名称。

struct Person {
1: i32 id,
2: string name,
3: bool isStudent
}

    3)异常:异常是一种特殊的结构体,用于表示错误或异常情况。它们通常用于在服务调用过程中传递错误信息。

exception MyException {
  1: i32 errorCode,
  2: string errorMessage
}

    4)集合:支持列表、集合和映射等集合类型。

list<i32> intList;
set<string> stringSet;
map<string, double> stringToDoubleMap;

    5)枚举:枚举是一种有限的、命名的整数类型,表示一组相关的常量。

enum Color {
  RED = 1,
  GREEN = 2,
  BLUE = 3
}

    6)服务接口:服务接口定义了一组相关的远程过程调用(RPC)方法,客户端可以调用这些方法来与服务端进行通信。

service MyService {
  i32 add(1: i32 a, 2: i32 b),
  string concatenate(1: string str1, 2: string str2)
}

  2. Thrift支持的协议

    1)TBinaryProtocol:二进制协议,使用二进制格式对数据进行序列化。这是 Thrift 默认的协议,提供了高效的序列化和压缩。

    2)TCompactProtocol:紧凑协议,使用变长编码对数据进行序列化,以减小数据包的大小。适用于带宽受限的网络环境。

    3)TJSONProtocol:JSON 协议,将数据序列化为 JSON 格式。适用于调试和与其他应用程序集成,但相对于二进制协议而言,JSON 格式会更大、更慢。

    4)TSimpleJSONProtocol:简单的 JSON 协议,与 TJSONProtocol 类似,但生成的 JSON 格式更为简单,适用于人类可读的场景。

    5)TDebugProtocol:调试协议,生成可读的文本输出,适用于调试目的。

  3. Thrift支持的传输层

    1)TSocket:使用传统的 TCP Socket 进行通信。通常用于在同一台机器上的进程之间或在网络上进行传输。

transport = TSocket(host, port)

    2)TFramedTransport:在数据传输之前,在每个消息的开头添加消息的长度信息。这样可以确保接收方能够正确地解析每个消息。

transport = TFramedTransport(TSocket(host, port))

    3)TBufferedTransport:缓冲传输,提供了一个缓冲区,可以在数据传输之前缓冲一定量的数据,以减少网络交互的次数。

transport = TBufferedTransport(TSocket(host, port))

    4)TZlibTransport:使用 zlib 压缩数据,可以减小数据传输的大小,适用于带宽受限的网络环境。

transport = TZlibTransport(TSocket(host, port))

    5)TMemoryBuffer:在内存中缓存数据,用于本地进程之间的通信,或者在需要对数据进行多次操作时。

transport = TMemoryBuffer()

    6)TFileTransport:文件传输,用于通过文件进行数据传输。适用于大量数据的离线传输场景。

transport = TFileTransport(file)

    7)TFastFramedTransport:类似于 TFramedTransport,但使用了更加紧凑的帧格式,适用于带宽敏感的场景。

transport = TFastFramedTransport(TSocket(host, port))

六、源码分析

  以后吧.......

七、参考博客

  1.  Archives | 梅林日志 (wizardmerlin.github.io)

  2.  Apache Thrift系列详解(一) - 概述与入门 - 知乎 (zhihu.com)

  3. Thrift - 维基百科,自由的百科全书 (wikipedia.org)