Apache Thrift 配置和使用指南

来源:互联网 发布:linux home空间 编辑:程序博客网 时间:2024/06/11 02:19

Thrift 安装

Mac 下 Thrift 安装

快速安装

使用 Mac 的包管理器 Homebrew。首先安装 Homebrew:

ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"

使用 Homebrew 安装 thrift:

brew install thrift

如需手动安装特定版本,请参考以下若干小节。

手动安装

首先编译安装 Thrift 的依赖 Boost 和 libevent,然后编译安装 Thrift。

安装 Boost

在 boost.org 下载 boost 库,解压进入文件夹,并通过以下命令编译:

./bootstrap.shsudo ./b2 threading=multi address-model=64 variant=release stage install

Boost 库是对 C++ 标准库提供扩展的一些 C++ 程序库的总称。

安装 libevent

在 libevent.org 下载 libevent, 解压并通过如下命令编译安装:

./configure --prefix=/usr/localmakesudo make install

libevent 是用 C 语言编写的、轻量级开源高性能网络库,基于事件驱动且支持跨平台。

安装 Apache Thrift

下载最新版本的 Apache Thrift,解压并通过如下命令编译安装:

./configure --prefix=/usr/local/  \--with-boost=/usr/local           \--with-libevent=/usr/local        \--without-ruby ## 不需要的语言可以通过 --without-[language] 去掉

运行时可能会报错:Bison version 2.5 or higher must be installed on the system!。参考 How to install bison on mac OSX 解决:

brew install bisonbrew link bison --force

brew link bison 是在系统路径下添加 bison 的 symlinks。在装完 thrift 之后记得:

brew unlink bison

Ubuntu 下 Thrift 配置

参考链接

[1] Debian/Ubuntu install
[2] Building from source
[3] Apache Thrift Tutorial

安装依赖

执行命令:

sudo apt-get install automake bison flex g++ git libboost1.55-all-dev libevent-dev libssl-dev libtool make pkg-config

安装 Thrift

在 Thrift 官网 下载最新的打包文件,解压后进入文件夹,输入如下命令编译安装:

./configure && make && sudo make install

Thrift C++ 实例

本节中我们实现一个简单的加减乘除计算器 C/S 实例。

基本过程

  1. 编写接口描述文件 calculator.thrift,定义数据类型和服务接口
  2. 编译 calculator.thrift 生成 gen-cpp 源代码文件夹
  3. 编写 server 代码,引用 gen-cpp 与 thrift 库目录编译
  4. 编写 client 代码,引用 gen-cpp 与 thrift 库目录编译
  5. 运行 ./server
  6. 运行 ./client

Thrift 脚本

假设服务端(Server)为客户端(Client)提供简单的数学运算功能,编写 calculator.thrift 脚本文件如下:

namespace cpp MathServerservice MathService{        i32 add (1:i32 a, 2:i32 b),        i32 sub (1:i32 a, 2:i32 b),        i32 mul (1:i32 a, 2:i32 b),        i32 div (1:i32 a, 2:i32 b),        i32 mod (1:i32 a, 2:i32 b)}

编译 Thrift 脚本的基本命令格式为:

thrift --gen <language> <Thrift filename>

如果在一个 .thrift 文件里包含了其他的 .thrift 文件,需要递归编译,执行:

thrift --gen -r <language> <Thrift filename>

本例中,我们执行如下命令编译:

thrift --gen cpp calculator.thrift

在当前目录下会生成一个 gen-cpp 文件夹。文件夹里包含 MathService.h/cpp, calculator_constants.h/cpp, calculator_types.h/cpp 和 MathService_server.skeleton.cpp 7 个文件。前 6 个文件用于接口定义,需要同时被 Client 和 Server 代码引用(调用或实现),而 MathService_server.skeleton.cpp 则提供了 Server 端代码的一个基本框架。

Server 程序

新建 calculator 文件夹,把 gen-cpp 复制进去,并将 gen-cpp 里的 MathService_server.skeleton.cpp 重命名为 server.cpp,移动到 server 文件夹。实现 server.cpp 后的完整代码如下:

// This autogenerated skeleton file illustrates how to build a server.// You should copy it to another filename to avoid overwriting it.#include "gen-cpp/MathService.h"#include <iostream>#include <thrift/protocol/TBinaryProtocol.h>#include <thrift/server/TSimpleServer.h>#include <thrift/transport/TServerSocket.h>#include <thrift/transport/TBufferTransports.h>using namespace ::apache::thrift;using namespace ::apache::thrift::protocol;using namespace ::apache::thrift::transport;using namespace ::apache::thrift::server;using boost::shared_ptr;using namespace  ::MathServer;class MathServiceHandler : virtual public MathServiceIf { public:  MathServiceHandler() {    // Your initialization goes here  }  int32_t add(const int32_t a, const int32_t b) {      return a + b;  }  int32_t sub(const int32_t a, const int32_t b) {      return a - b;  }  int32_t mul(const int32_t a, const int32_t b) {      return a * b;  }  int32_t div(const int32_t a, const int32_t b) {      return a / b;  }  int32_t mod(const int32_t a, const int32_t b) {      return a % b;  }};int main(int argc, char** argv) {  int port = 9090;  shared_ptr<MathServiceHandler> handler(new MathServiceHandler());  shared_ptr<TProcessor> processor(new MathServiceProcessor(handler));  shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));  shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());  shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());  TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);  std::cout << "Start server..." << std::endl;  server.serve();  return 0;}

Client 程序

在 calculator 文件夹里新建 client.cpp 文件,代码如下:

#include <iostream>#include <thrift/protocol/TBinaryProtocol.h>#include <thrift/transport/TSocket.h>#include <thrift/transport/TTransportUtils.h>#include "gen-cpp/MathService.h"using namespace std;using namespace apache::thrift;using namespace apache::thrift::protocol;using namespace apache::thrift::transport;using boost::shared_ptr;using namespace  ::MathServer;int main(int argc, char** argv) {  int port = 9090;  boost::shared_ptr<TTransport> socket(new TSocket("localhost", port));  boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));  boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));  MathServiceClient client(protocol);  try {      transport->open();      cout << "1 + 1 = " << client.add(1, 1) << endl;      cout << "1 * 2 = " << client.mul(1, 2) << endl;      cout << "8 / 2 = " << client.div(8, 2) << endl;      transport->close();    } catch (TException& tx) {      cout << "ERROR: " << tx.what() << endl;    }}

编译

用 g++ 编译,先针对各个 .cpp 文件生成 .o 目标,然后链接 thrift 库,生成可执行文件 client 和 server。由于 thrift 里用到 c++11 里的 bind 方法,需要指定 -std=c++11。假设 thrift 库安装在 /usr/local/lib 里,thrift 的头文件在 /usr/local/include/thrift 中,则完整的编译命令如下:

# build object filesg++ -I/usr/local/include -std=c++11 -c -o \    gen-cpp/calculator_constants.o gen-cpp/calculator_constants.cppg++ -I/usr/local/include -std=c++11 -c -o \    gen-cpp/calculator_types.o gen-cpp/calculator_types.cppg++ -I/usr/local/include -std=c++11 -c -o \    gen-cpp/MathService.o gen-cpp/MathService.cpp# build server.og++ -I/usr/local/include -std=c++11 -c -o \    server.o server.cpp# build client.og++ -I/usr/local/include -std=c++11 -c -o \    client.o client.cpp# build target files: client, serverg++ -L/usr/local/lib -lthrift -o server server.o \    gen-cpp/calculator_constants.o gen-cpp/calculator_types.o \    gen-cpp/MathService.og++ -L/usr/local/lib -lthrift -o client client.o \    gen-cpp/calculator_constants.o gen-cpp/calculator_types.o \    gen-cpp/MathService.o# clear *.orm ./*.o gen-cpp/*.o

可以直接执行以上命令,也可以将以上命令写进一个 build.sh 文件里,然后执行:

sh ./build.sh

生成完 client 和 server 后,分别在两个终端执行 ./server./client,可以分别看到 Start server...1 + 1 = 2 ...

综上。

Thrift 脚本语法

Thrift 用于跨语言的 RPC 通信,因此其接口定义文件 *.thrift 中包含的数据结构与函数定义必须对于不同语言都适用。官网的 Thrift Wiki Tutorial 基本包含了所有的 Thrift 语法,无须赘述,这里只是把它复制过来:

## Thrift Tutorial# Mark Slee (mcslee@facebook.com)## This file aims to teach you how to use Thrift, in a .thrift file. Neato. The# first thing to notice is that .thrift files support standard shell comments.# This lets you make your thrift file executable and include your Thrift build# step on the top line. And you can place comments like this anywhere you like.## Before running this file, you will need to have installed the thrift compiler# into /usr/local/bin./** * The first thing to know about are types. The available types in Thrift are: * *  bool        Boolean, one byte *  byte        Signed byte *  i16         Signed 16-bit integer *  i32         Signed 32-bit integer *  i64         Signed 64-bit integer *  double      64-bit floating point value *  string      String *  map<t1,t2>  Map from one type to another *  list<t1>    Ordered list of one type *  set<t1>     Set of unique elements of one type * * Did you also notice that Thrift supports C style comments? */// Just in case you were wondering... yes. We support simple C comments too./** * Thrift files can reference other Thrift files to include common struct * and service definitions. These are found using the current path, or by * searching relative to any paths specified with the -I compiler flag. * * Included objects are accessed using the name of the .thrift file as a * prefix. i.e. shared.SharedObject */include "shared.thrift"/** * Thrift files can namespace, package, or prefix their output in various * target languages. */namespace cpp tutorialnamespace java tutorialphp_namespace tutorialnamespace perl tutorialnamespace smalltalk.category Thrift.Tutorial/** * Thrift lets you do typedefs to get pretty names for your types. Standard * C style here. */typedef i32 MyInteger/** * Thrift also lets you define constants for use across languages. Complex * types and structs are specified using JSON notation. */const i32 INT32CONSTANT = 9853const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}/** * You can define enums, which are just 32 bit integers. Values are optional * and start at 1 if not supplied, C style again. *              ^ ThriftIDL page says "If no constant value is supplied, *   the value is either 0 for the first element, or one greater than the *   preceding value for any subsequent element" so I'm guessing that's a bug. *   PS: http://enel.ucalgary.ca/People/Norman/enel315_winter1997/enum_types/ states that if values are not supplied, they start at 0 and not 1. */enum Operation {  ADD = 1,  SUBTRACT = 2,  MULTIPLY = 3,  DIVIDE = 4}/** * Structs are the basic complex data structures. They are comprised of fields * which each have an integer identifier, a type, a symbolic name, and an * optional default value. * * Fields can be declared "optional", which ensures they will not be included * in the serialized output if they aren't set.  Note that this requires some * manual management in some languages. */struct Work {  1: i32 num1 = 0,  2: i32 num2,  3: Operation op,  4: optional string comment,}/** * Structs can also be exceptions, if they are nasty. */exception InvalidOperation {  1: i32 what,  2: string why}/** * Ahh, now onto the cool part, defining a service. Services just need a name * and can optionally inherit from another service using the extends keyword. */service Calculator extends shared.SharedService {  /**   * A method definition looks like C code. It has a return type, arguments,   * and optionally a list of exceptions that it may throw. Note that argument   * lists and exception lists are specified using the exact same syntax as   * field lists in struct or exception definitions.  NOTE: Overloading of   * methods is not supported; each method requires a unique name.   */   void ping(),   i32 add(1:i32 num1, 2:i32 num2),   i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),   /**    * This method has an oneway modifier. That means the client only makes    * a request and does not listen for any response at all. Oneway methods    * must be void.    *    * The server may execute async invocations of the same client in parallel/    * out of order.    */   oneway void zip(),}/** * It's possible to declare more than one service per Thrift file. */service CalculatorExtreme extends shared.SharedService {    void pingExtreme(),}/** * That just about covers the basics. Take a look in the test/ folder for more * detailed examples. After you run this file, your generated code shows up * in folders with names gen-<language>. The generated code isn't too scary * to look at. It even has pretty indentation. */

参考链接

[1] Apache Thrift OS X Setup
[2] mac os x10.10 安装thrift
[3] Thrift C++ Tutorial

0 0