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

C语言Thrift库使用(从零开始构建高性能跨语言RPC服务)

在现代分布式系统中,不同服务之间需要高效、可靠的通信机制。Apache Thrift 是一个由 Facebook 开源的跨语言 RPC(远程过程调用)框架,支持包括 C、C++、Java、Python、Go 等数十种编程语言。本文将手把手教你如何在 C语言 中使用 Thrift 库,即使是编程小白也能轻松上手。

什么是 Thrift?

Thrift 的核心思想是:通过定义一套接口描述语言(IDL),自动生成客户端和服务端代码,从而实现跨语言通信。你只需编写一次接口定义,Thrift 编译器(thrift compiler)就能为你生成各种语言的绑定代码。

C语言Thrift库使用(从零开始构建高性能跨语言RPC服务) C语言 Thrift  Apache C教程 RPC C语言微服务通信 第1张

准备工作

要使用 C 语言开发 Thrift 服务,你需要完成以下步骤:

  1. 安装 Thrift 编译器(thrift)
  2. 安装 C 语言的 Thrift 运行时库(libthrift)
  3. 编写 .thrift 接口定义文件
  4. 生成 C 语言代码
  5. 编写服务端和客户端逻辑

第一步:安装 Thrift 工具链

以 Ubuntu/Debian 系统为例:

# 安装依赖sudo apt-get install build-essential libboost-dev libevent-dev# 下载并编译 Thrift(以 0.16.0 为例)wget https://archive.apache.org/dist/thrift/0.16.0/thrift-0.16.0.tar.gztar -xzf thrift-0.16.0.tar.gzcd thrift-0.16.0./configure --with-cpp --without-python --without-javamakesudo make install# 安装 C 语言运行时库sudo apt-get install libthrift-dev

第二步:编写 .thrift 接口文件

创建一个名为 calculator.thrift 的文件,定义一个简单的计算器服务:

// calculator.thriftnamespace c calcenum Operation {  ADD = 1,  SUBTRACT = 2,  MULTIPLY = 3,  DIVIDE = 4}struct Work {  1: i32 num1,  2: i32 num2,  3: Operation op}service Calculator {  i32 calculate(1: Work w),  void ping()}

这里我们定义了一个 Calculator 服务,包含两个方法:calculateping。注意 namespace c calc 表示生成的 C 代码将放在 calc 命名空间下(在 C 中体现为前缀)。

第三步:生成 C 语言代码

运行 Thrift 编译器:

thrift --gen c calculator.thrift

执行后会生成 gen-c/ 目录,里面包含所有 C 语言所需的头文件和源文件,如 calc_calculator.hcalc_types.h 等。

第四步:编写服务端代码

创建 server.c 文件:

#include <thrift/c_glib/thrift.h>#include <thrift/c_glib/transport/thrift_server_socket.h>#include <thrift/c_glib/transport/thrift_buffered_transport_factory.h>#include <thrift/c_glib/protocol/thrift_binary_protocol_factory.h>#include "gen-c/calc_calculator.h"#include "gen-c/calc_types.h"// 实现 Calculator 接口typedef struct _CalculatorHandler CalculatorHandler;typedef struct _CalculatorHandlerClass CalculatorHandlerClass;struct _CalculatorHandler {  GObject parent;};struct _CalculatorHandlerClass {  GObjectClass parent_class;};G_DEFINE_TYPE(CalculatorHandler, calculator_handler, G_TYPE_OBJECT)static void calculator_handler_ping(ThriftIf *iface, GError **error) {  g_print("ping() called\n");}static gint32 calculator_handler_calculate(ThriftIf *iface, gpointer w, GError **error) {  Work *work = (Work *)w;  switch (work->op) {    case ADD: return work->num1 + work->num2;    case SUBTRACT: return work->num1 - work->num2;    case MULTIPLY: return work->num1 * work->num2;    case DIVIDE:      if (work->num2 == 0) {        g_set_error(error, THRIFT_ERROR, THRIFT_ERROR_PROTOCOL, "Division by zero");        return 0;      }      return work->num1 / work->num2;    default:      g_set_error(error, THRIFT_ERROR, THRIFT_ERROR_PROTOCOL, "Invalid operation");      return 0;  }}static void calculator_handler_init(CalculatorHandler *self) {}static void calculator_handler_class_init(CalculatorHandlerClass *klass) {  ThriftIfClass *if_class = THRIFT_IF_CLASS(klass);  if_class->ping = calculator_handler_ping;  if_class->calculate = calculator_handler_calculate;}int main(void) {  g_type_init();  CalculatorHandler *handler = g_object_new(TYPE_CALCULATOR_HANDLER, NULL);  CalculatorProcessor *processor = calculator_processor_new(THRIFT_IF(handler));  ThriftServerTransport *server_transport = thrift_server_socket_new_with_host_port("localhost", 9090);  ThriftTransportFactory *transport_factory = thrift_buffered_transport_factory_new();  ThriftProtocolFactory *protocol_factory = thrift_binary_protocol_factory_new();  ThriftSimpleServer *server = g_object_new(THRIFT_TYPE_SIMPLE_SERVER,                                           "processor", processor,                                           "server_transport", server_transport,                                           "input_transport_factory", transport_factory,                                           "output_transport_factory", transport_factory,                                           "input_protocol_factory", protocol_factory,                                           "output_protocol_factory", protocol_factory,                                           NULL);  g_print("Starting server on port 9090...\n");  thrift_server_serve(THRIFT_SERVER(server), NULL);  g_object_unref(server);  return 0;}

第五步:编写客户端代码

创建 client.c 文件:

#include <thrift/c_glib/thrift.h>#include <thrift/c_glib/transport/thrift_socket.h>#include <thrift/c_glib/transport/thrift_buffered_transport.h>#include <thrift/c_glib/protocol/thrift_binary_protocol.h>#include "gen-c/calc_calculator.h"#include "gen-c/calc_types.h"int main(void) {  g_type_init();  ThriftSocket *socket = g_object_new(THRIFT_TYPE_SOCKET,                                      "hostname", "localhost",                                      "port", 9090,                                      NULL);  ThriftTransport *transport = thrift_buffered_transport_new(THRIFT_TRANSPORT(socket));  ThriftProtocol *protocol = thrift_binary_protocol_new(transport, transport);  CalculatorClient *client = calculator_client_new(protocol);  // 测试 ping  calculator_client_ping(client, NULL);  g_print("ping() success!\n");  // 测试 calculate  Work *work = work_new();  work->num1 = 10;  work->num2 = 5;  work->op = ADD;  gint32 result;  calculator_client_calculate(client, &result, work, NULL);  g_print("10 + 5 = %d\n", result);  g_object_unref(client);  return 0;}

第六步:编译与运行

使用以下命令编译服务端和客户端(假设所有文件在同一目录):

# 编译服务端gcc -o server server.c gen-c/*.c `pkg-config --cflags --libs thrift_c_glib`# 编译客户端gcc -o client client.c gen-c/*.c `pkg-config --cflags --libs thrift_c_glib`

先运行服务端:

./server

再打开另一个终端运行客户端:

./client

你应该看到输出:

ping() calledping() success!10 + 5 = 15

总结

通过本教程,你已经学会了如何使用 C语言 Thrift 构建一个完整的 RPC 服务。Thrift 不仅支持 Apache Thrift C教程 中的基础功能,还能用于构建高性能的微服务系统。掌握 Thrift RPC C语言 开发技能,将帮助你在 C语言微服务通信 领域打下坚实基础。

虽然 C 语言的 Thrift 实现相对复杂(基于 GLib 对象系统),但其性能优异,适用于对资源敏感的嵌入式或高性能服务器场景。建议初学者先理解 IDL 定义和代码生成机制,再逐步深入服务端/客户端实现细节。

现在,你可以尝试扩展这个计算器服务,比如添加更多运算、错误处理或异步调用,进一步提升你的 Thrift 实战能力!