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 实例。
基本过程
- 编写接口描述文件 calculator.thrift,定义数据类型和服务接口
- 编译 calculator.thrift 生成 gen-cpp 源代码文件夹
- 编写 server 代码,引用 gen-cpp 与 thrift 库目录编译
- 编写 client 代码,引用 gen-cpp 与 thrift 库目录编译
- 运行 ./server
- 运行 ./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
- Apache Thrift 配置和使用指南
- Apache Thrift 配置环境
- Apache Thrift 配置环境
- Thrift使用指南
- Thrift使用指南
- Thrift使用指南
- Thrift使用指南
- Thrift使用指南
- Thrift使用指南
- Thrift使用指南
- Thrift使用指南
- Thrift使用指南
- Thrift使用指南
- thrift使用指南
- Thrift使用指南
- Thrift使用指南
- Thrift使用指南
- Thrift使用指南
- 在 C# 中使用 C++
- MySQL索引的使用
- 第6天HBase笔记
- 关于SurfaceView横竖屏切换显示问题
- iOS 基于环信SDK实现即时通讯-文字聊天
- Apache Thrift 配置和使用指南
- selenium 如何获取分页数据
- Retrofit2学习笔记-1
- 素数筛法详解
- javascript中的异步编程的4种方法
- 数据结构---链表和数组
- 从Visual Studio看微软20年技术变迁
- linux 使用终端命令安装chrome
- 记我的腾讯电话面