Apache Thrift 官方教程实战:从 .thrift IDL 到多语言客户端/服务器

发布时间:2026/9/15 23:03:17
Apache Thrift 官方教程实战:从 .thrift IDL 到多语言客户端/服务器 Apache Thrift 官方教程实战从 .thrift IDL 到多语言客户端/服务器【免费下载链接】thriftApache Thrift项目地址: https://gitcode.com/GitHub_Trending/thr/thrift本教程是 Apache Thrift 仓库中 tutorial/ 目录的完整实战指南。它以官方 tutorial/README.md 的六步流程为主线带你走完「安装编译器 → 阅读 IDL 语法 → 生成代码 → 编写客户端/服务器」的完整链路。读完本文你将能够读懂并编写 .thrift 接口定义文件用thrift编译器为任意支持的语言生成代码并在 C、Python、Node.js 等语言中跑通自己的第一个 RPC 服务。Thrift 的分层抽象传输层 Transport → 协议层 Protocol → 服务层 Servertutorial 中所有示例的客户端与服务器代码都建立在这条栈之上。一、教程全景tutorial 目录里有什么官方教程位于仓库的 tutorial/ 目录核心文件与角色如下文件/目录作用tutorial.thrift教学用 IDL 文件覆盖 Thrift 语法的主要特性是教程的主体shared.thrift被 tutorial.thriftinclude的公共定义文件演示跨文件引用README.md官方教程操作说明本文基于它展开cpp / py / java / nodejs / rb / go / rs / netstd / haxe / dart / erl / ocaml / perl / php / cl / d / delphi / c_glib 等子目录各语言的示例客户端与服务器实现Makefile.am构建脚本按编译开关WITH_CPP、WITH_PYTHON、WITH_JAVA等决定参与构建的语言子目录并默认执行thrift --gen html -r tutorial.thrift生成 HTML 版文档官方 tutorial/README.md 将学习路径浓缩为六步安装 Thrift 编译器与所需语言的运行时库依据顶层 README.md 的说明通读tutorial.thrift学习 Thrift 文件的语法用编译器为目标语言生成代码查看生成代码在各语言目录中查看示例客户端/服务器代码完成开始构建自己的项目。下文逐一展开。二、环境准备安装编译器与语言库教程第一步要求安装 Thrift 编译器thrift命令与目标语言的运行时库。编译器的安装方式请以仓库顶层 README.md 为准其核心流程为标准的 autotools 构建./bootstrap.sh # 生成 configure 脚本从源码首次构建时需要 ./configure # 探测依赖并生成 Makefile make # 编译编译器与各语言库 make install # 安装到系统路径如 /usr/local/bin几点补充若 Boost 安装在非标准路径如/usr/local可在configure时显式指定Python 模块的安装路径可通过PY_PREFIX变量调整make check会运行跨语言测试即使某个语言构建失败整体仍会继续并输出汇总报告需要卸载时执行make uninstall部分语言的包必须使用各自的构建工具手动安装如 Java 的 Gradle、Go 的go mod等。tutorial.thrift的注释中提到运行本教程前应保证编译器已安装到/usr/local/bin。安装完成后可用thrift -version验证。三、阅读 tutorial.thriftIDL 语法速成tutorial/tutorial.thrift 是一份「会说话的语法教材」——它把 Thrift 语言的主要特性都写进了注释里。逐节拆解如下。3.1 注释风格.thrift文件支持三类注释与 C/C 完全一致#行注释shell 风格//行注释/* ... */与/** ... */块注释后者常被用作文档注释。官方注释还提示了一个技巧可以在文件首行使用#让 .thrift 文件本身可执行并把编译步骤写在首行。3.2 基础类型Thrift 内置的基础类型如下原文完整列表类型说明bool布尔值占一个字节i8byte有符号 8 位整数i16有符号 16 位整数i32有符号 32 位整数i64有符号 64 位整数double64 位浮点数string字符串binary字节数组Blobmapt1,t2键值映射listt1有序列表sett1唯一元素集合3.3 include跨文件引用Thrift 文件可以引用其他 Thrift 文件以复用公共的 struct 与 service 定义include shared.thrift查找规则先在当前路径查找也可通过编译器的-I参数指定额外搜索路径。被包含文件中的对象使用「文件名前缀」访问例如 shared.thrift 中定义的SharedStruct在引用方写作shared.SharedStruct。3.4 namespace控制各语言输出包名namespace cl tutorial namespace cpp tutorial namespace d tutorial namespace dart tutorial namespace java tutorial namespace php tutorial namespace perl tutorial namespace haxe tutorial namespace netstd tutorialnamespace用于为不同目标语言指定生成的包/模块/命名空间。注意语言间有差异D 语言中shared与关键字冲突因此 shared.thrift 特意使用namespace d share规避。3.5 typedef 与 consttypedef i32 MyInteger const i32 INT32CONSTANT 9853 const mapstring,string MAPCONSTANT {hello:world, goodnight:moon}typedef为类型起别名C 风格const定义跨语言共享的常量。复杂类型map、list、struct的常量使用 JSON 风格字面量书写。3.6 字符串字面量与转义规则tutorial.thrift用大段注释给出了字符串字面量的精确规则可用双引号或单引号包裹两种写法等价适用于包括include与注解值在内的所有出现字符串的位置字面量必须在起始行内结束不包裹字面量的引号字符可直接使用如dont或say hi支持四种转义序列\双引号、\单引号、\\反斜杠、\n换行、\r回车、\t制表符反斜杠后跟其他任何字符都是错误字面意义上的反斜杠必须写双份C:\\Temp表示字符串C:\Temp不支持\x41或\u00e4这类数字转义非 ASCII 字符直接书写。3.7 enum32 位整数枚举enum Operation { ADD 1, SUBTRACT 2, MULTIPLY 3, DIVIDE 4 }枚举本质上是 32 位整数值可省略省略时从 1 开始递增C 风格。3.8 struct结构化数据struct Work { 1: i32 num1 0, 2: i32 num2, 3: Operation op, 4: optional string comment, }每个字段由四部分组成整数编号、类型、符号名、可选的默认值。字段可声明为optional其语义是未设置时不会出现在序列化输出中。官方注释提醒这在部分语言里需要手动管理字段的「是否已设置」状态例如 C 生成的__isset位标志。3.9 exception可抛出的结构exception InvalidOperation { 1: i32 whatOp, 2: string why }exception是特殊的 struct语法与 struct 完全相同但语义上是 RPC 方法可能抛出的异常。在 C 生成代码中它会继承TException客户端可以用catch (InvalidOperation io)捕获见 CppClient.cpp。3.10 service定义 RPC 接口service Calculator extends shared.SharedService { void ping(), i32 add(1:i32 num1, 2:i32 num2), i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), oneway void zip() }要点服务可以继承其他服务extends shared.SharedService此时 Calculator 自动获得getStruct方法方法定义形似 C 函数返回类型 参数列表 可选的throws异常列表参数列表与异常列表的书写语法和 struct 字段列表完全一致oneway void zip()oneway修饰符表示客户端只发送请求、完全不等响应因此oneway方法返回值必须是void。tutorial.thrift结尾的注释指出更完整的示例可继续阅读仓库的 test/ 目录如 test/ThriftTest.thrift生成代码会出现在gen-language目录中。四、编译生成代码thrift 命令教程第三步给出了两条命令第一条为展示命令本身第二条为实际编译指令$ thrift $ thrift -r --gen cpp tutorial.thrift参数含义-r--recurse递归处理include的文件——由于tutorial.thrift引用了shared.thrift该参数会一并为其生成代码--gen cpp指定目标语言生成器这里是 C若被包含文件不在当前目录可用-I path追加搜索路径对应include一节提到的查找规则。把cpp换成其他语言名即可切换生成器--gen java、--gen py、--gen js:node、--gen go、--gen rs、--gen netstd、--gen rb、--gen php、--gen haxe、--gen dart、--gen lua等。生成结果输出到gen-language目录如gen-cpp/、gen-py/这也是各语言示例代码中#include ../gen-cpp/Calculator.h、sys.path.append(gen-py)、require(./gen-nodejs/Calculator)等引用的来源。五、生成代码长什么样教程第四步是「查看生成代码」。以 C 为例gen-cpp/下会出现tutorial_types.h/.cppenum、struct、exception 的 C 数据类型与序列化方法shared_types.h/.cpp被 include 的SharedStruct等类型Calculator.h/.cpp服务接口CalculatorIf、客户端CalculatorClient、处理器CalculatorProcessor及工厂类shared_constants.h/.cpp、tutorial_constants.h/.cpp常量定义。生成的接口层设计值得注意每个服务会生成一对「接口 处理器」——服务端业务类继承接口如CalculatorIf而生成的CalculatorProcessor负责把线上的协议消息分发到业务方法。正如教程注释所说生成代码「并不吓人甚至有着漂亮的缩进」。六、各语言示例客户端/服务器教程第五步指向各语言目录的示例代码。所有语言实现都遵循同一套分层栈Transport字节传输→ Protocol消息编解码→ Client/Processor业务。6.1 C完整的分层栈与服务器类型tutorial/cpp/CppServer.cpp 展示了服务端三件套TThreadedServer server( std::make_sharedCalculatorProcessorFactory(std::make_sharedCalculatorCloneFactory()), std::make_sharedTServerSocket(9090), //port std::make_sharedTBufferedTransportFactory(), std::make_sharedTBinaryProtocolFactory()); server.serve();处理器CalculatorProcessorFactoryCalculatorCloneFactory的组合用于每连接一个 handler 实例。CalculatorCloneFactory::getHandler中可以从TConnectionInfo取出底层TSocket打印对端主机、地址、端口等信息是实现每连接状态如独立日志的推荐方式如果不需要每连接状态可直接使用CalculatorProcessor 单一CalculatorHandler代码中以注释形式给出传输TServerSocket(9090)监听端口TBufferedTransportFactory提供缓冲协议TBinaryProtocolFactory使用二进制协议。业务 handler 继承生成的CalculatorIf并实现各方法。calculate中展示了服务端抛异常的写法——除数为 0 时构造InvalidOperation并throw由协议层编码后送回客户端case Operation::DIVIDE: if (work.num2 0) { InvalidOperation io; io.whatOp work.op; io.why Cannot divide by 0; throw io; } val work.num1 / work.num2; break;同一个文件还以注释形式给出了另外两种服务器类型方便对比选型服务器类型特点TSimpleServer单连接、不派生线程最简单TThreadedServer每连接一个线程本示例默认TThreadPoolServer通过ThreadManager::newSimpleThreadManager(workerCount)维护固定工作线程池复用线程、限制并发连接数tutorial/cpp/CppClient.cpp 展示客户端构造的标准四层栈std::shared_ptrTTransport socket(new TSocket(localhost, 9090)); std::shared_ptrTTransport transport(new TBufferedTransport(socket)); std::shared_ptrTProtocol protocol(new TBinaryProtocol(transport)); CalculatorClient client(protocol); transport-open();客户端演示了ping()无参调用、add()简单 RPC、调用calculate并捕获服务端抛出的InvalidOperationcatch (InvalidOperation io)后读取io.why、以及复杂类型返回——C 对复杂类型使用引用传参返回以避免昂贵的拷贝client.getStruct(ss, 1)后读取ss。6.2 Python同样的四层栈tutorial/py/PythonClient.py 与 tutorial/py/PythonServer.py 结构完全对应# 客户端socket - buffered transport - binary protocol - client transport TSocket.TSocket(localhost, 9090) transport TTransport.TBufferedTransport(transport) # 注释强调缓冲至关重要裸 socket 很慢 protocol TBinaryProtocol.TBinaryProtocol(transport) client Calculator.Client(protocol) transport.open()# 服务端processor server socket transport factory protocol factory handler CalculatorHandler() processor Calculator.Processor(handler) transport TSocket.TServerSocket(host127.0.0.1, port9090) tfactory TTransport.TBufferedTransportFactory() pfactory TBinaryProtocol.TBinaryProtocolFactory() server TServer.TSimpleServer(processor, transport, tfactory, pfactory) server.serve()Python 版本同样给出了多线程服务器的备选TServer.TThreadedServer与TServer.TThreadPoolServer。Python 客户端还需把生成代码目录加入sys.pathsys.path.append(gen-py)并引用生成模块from tutorial import Calculator、from tutorial.ttypes import InvalidOperation, Operation, Work。6.3 Node.js回调风格处理器tutorial/nodejs/NodeServer.js 展示了 Node.js 的写法——处理器是一组回调函数每个方法通过result(err, data)返回var server thrift.createServer(Calculator, { ping: function (result) { console.log(ping()); result(null); }, add: function (n1, n2, result) { result(null, n1 n2); }, calculate: function (logid, work, result) { /* ... */ } });异常通过把ttypes.InvalidOperation实例传给result的第一个参数抛出。同一目录还提供 Promise 风格版本 NodeClientPromise.js 与 NodeServerPromise.js。6.4 Java一条命令跑通tutorial/java/README.md 给出了 Java 教程的运行方式。先编译 Java 库thrift/lib/java$ make # 或 thrift/lib/java$ gradle assemble然后一键同时启动服务端与客户端thrift/tutorial/java$ make tutorial # 或 thrift/tutorial/java$ gradle tutorial也可以分两个终端分别运行thrift/tutorial/java$ make tutorialserver thrift/tutorial/java$ make tutorialclient # 或 thrift/tutorial/java$ gradle tutorialServer thrift/tutorial/java$ gradle tutorialClient对应的业务实现位于 tutorial/java/src/CalculatorHandler.java。6.5 其他语言一览教程目录还覆盖了大量语言均可按「生成代码 运行示例」的同一套路使用Gotutorial/go/src/server.go含handler.go、client.go目录内自带server.crt/server.key演示 TLSRusttutorial/rs/Cargo 工程见 tutorial/rs/README.mdRubyRubyServer.rb 与 RubyClient.rb.NET/C#tutorial/netstd/Client/Server 两个工程Erlangserver.erl、client.erl并有json_client.erl演示 JSON 协议Darttutorial/dart/含 Web 客户端与 console 客户端以及Haxe多种目标平台 hxml、Perl、PHP、Delphi、OCaml、Common Lispcl、D含async_client.d异步示例、C 语言c_glib等。Makefile.am 中的SUBDIRS开关说明构建时各语言目录的参与由./configure阶段的语言开关WITH_CPP、WITH_PYTHON、WITH_JAVA等决定按需启用即可。七、运行与验证教程中的服务端默认监听9090端口。以 C 为例编译运行后启动服务端TThreadedServer每连接一线程serve()阻塞运行控制台会打印ping()、add(...)、calculate(...)等调用日志启动客户端应依次输出ping()、1 1 2、除零时捕获到InvalidOperation: Cannot divide by 0、15 - 10 5、以及Received log: ...getStruct 从服务端日志中取回结果。需要自行验证完整链路时可在源码根目录执行make check运行整套跨语言测试即使个别语言失败也会继续并汇总。若使用 Docker顶层 README.md 还提供了与 CI 一致的容器构建方式。八、下一步教程本身「刻意保持简短」它只负责把你领进门。继续深入的方向包括更完整的 IDL 特性查看 test/ 下的测试用 .thrift 文件如 test/ThriftTest.thrift覆盖联合体 union、容器嵌套、注解等更多语法协议与传输本教程统一使用二进制协议 缓冲传输仓库 doc/specs/ 下有二进制协议、Compact 协议、JSON 等规范文档各语言库中还提供TCompactProtocol、TFramedTransport、TSaslTransport等变体lib 目录各语言运行时库源码位于 lib/LANGUAGES.md 列出了语言支持矩阵高级服务器模型对比 TSimpleServer / TThreadedServer / TThreadPoolServer 乃至非阻塞 TNonblockingServer可阅读 lib/cpp/src/thrift/server/ 下的实现。至此官方教程的六步已经全部走完——你现在已经掌握了从编写 IDL、生成代码到搭建多语言 RPC 服务的完整能力可以开始构建自己的项目了。【免费下载链接】thriftApache Thrift项目地址: https://gitcode.com/GitHub_Trending/thr/thrift创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考