Apache Thrift的简单使用

Apache Thrift的简单使用

----------------------

 

1. 简单介绍

Thrift是Facebook的一个开源项目,主要是一个跨语言的服务开发框架。它有一个代码生成器来对它所定义的IDL定义文件自动生成服务代码框架。用户只要在其之前进行二次开发就行,对于底层的RPC通讯等都是透明的。目前它支持的语言有C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk, and OCaml.

 

2. 下载与安装

可以在http://incubator.apache.org/thrift/download/去下载它的最新版本,目前最新版本是0.5.0。另外你也可以check出它的svn,方法如下:

svn co http://svn.apache.org/repos/asf/thrift/trunk thrift

cd thrift

 

在它的jira中看到,它的0.6版本也很快就会出来了。

 

我的本本是debian 6.0,如果用ubuntu的兄弟安装方法也是一样的

[c-sharp]  view plain copy
  1. tar -zxvf thrift-0.5.0.tar.gz  
  2. cd thrift-0.5.0  
  3. ./configure  
  4. make   
  5. sudo make install  
 

 

这时thrift的代码生成器和一些库文件就生成好了。

 

你可以用如下命令看一下thrift的版本信息

 

[c-sharp]  view plain copy
  1. thrift -version  
 

 

3. 一个简单的例子

在thrift源代码目录有一个叫tutorial的目录,进行其中后运行thrift命令生成相应的服务代码:

[c-sharp]  view plain copy
  1. $ thrift -r --gen cpp tutorial.thrift // -r对其中include的文件也生成服务代码 -gen是生成服务代码的语言  
 

 

运行完之后会在当前目录看到一个gen-cpp目录,其中就是thrfit命令生成的代码

 

这时你cd到tutorial/cpp目录,运行make,生成相应的CppServer与CppClient程式。

 

这时你可以用./CppServer运行服务端,让其监听一个特定的端口

 

这时你可以用./CppClient运行客户端程式,让其去连接服务端,调用其所对应的服务。默认调用后会输出如下信息:

 

[c-sharp]  view plain copy
  1. lemo@debian:~/Workspace/Facebook/Thrift/thrift-0.5.0/tutorial/cpp$ ./CppServer  
  2. Starting the server...  
  3. ping()  
  4. add(1,1)  
  5. calculate(1,{4,1,0})  
  6. calculate(1,{2,15,10})  
  7. getStruct(1)  
 

 

如果你的终端中也出现了如上的信息,恭喜你,运行成功了。如果在运行CppServer的时候找不到动态库,看看你是不是运行了make install,如果运行了,再运行一下sudo ldconfig试试。再用ldd CppServer看一下它有没有找到相应的动态库了。

 

4. 例子分析

 

4.1 Thrift IDL的分析

 

这边有两个IDL文件,内容如下:

 

[c-sharp]  view plain copy
  1. shared.thrift  
  2. ---------------  
  3. **  
  4.  * This Thrift file can be included by other Thrift files that want to share  
  5.  * these definitions.  
  6.  */  
  7. namespace cpp shared  
  8. namespace java shared  
  9. namespace perl shared  
  10. // 这里定义了一个结构体,没有定义方法,对应于生成的代码在gen-cpp中的shared_types.h中,其中有一个class叫SharedStruct,  
  11. // 有没有看到其中有两个方法叫read和write,这就是用来对其进行序列化与把序列化的方法.  
  12. // 对了,其中的i32是Thrift IDL中定义的变量类型,对应于c++语言中的int32_t  
  13. struct SharedStruct {      
  14.   1: i32 key  
  15.   2: string value  
  16. }  
  17. // 这里定义的一个服务,它语义上类似于面向对象中的定义一个接口,thrift的编译器会对其产生一套实现其接口的客户端与服务端方法  
  18. // 服务的一般定义格式如下  
  19. // service <name>  
  20. // <returntype> <name>(<arguments>)  
  21. // [ throws (<exceptions>)]  
  22. //   ...  
  23. // }  
  24. service SharedService {  
  25.   SharedStruct getStruct(1: i32 key)  
  26. }  
  27. tutorial.thrift  
  28. ----------------  
  29. /** 
  30.  * Thrift files can reference other Thrift files to include common struct 
  31.  * and service definitions. These are found using the current path, or by 
  32.  * searching relative to any paths specified with the -I compiler flag. 
  33.  * 
  34.  * Included objects are accessed using the name of the .thrift file as a 
  35.  * prefix. i.e. shared.SharedObject 
  36.  */  
  37.  // 这个IDL包含了另一个IDL,也就是说另一个IDL中的对象与服务对其时可见的  
  38. include "shared.thrift"  
  39. /** 
  40.  * Thrift files can namespace, package, or prefix their output in various 
  41.  * target languages. 
  42.  */  
  43.  // 这里定义了一些语言的namespace空间  
  44. namespace cpp tutorial  
  45. namespace java tutorial  
  46. namespace php tutorial  
  47. namespace perl tutorial  
  48. /** 
  49.  * Thrift lets you do typedefs to get pretty names for your types. Standard 
  50.  * C style here. 
  51.  */  
  52.  // 自定义类型  
  53. typedef i32 MyInteger  
  54. /** 
  55.  * Thrift also lets you define constants for use across languages. Complex 
  56.  * types and structs are specified using JSON notation. 
  57.  */  
  58.  // 定义一些变量  
  59. const i32 INT32CONSTANT = 9853  
  60. const map<string,string> MAPCONSTANT = {'hello':'world''goodnight':'moon'}  
  61. /** 
  62.  * You can define enums, which are just 32 bit integers. Values are optional 
  63.  * and start at 1 if not supplied, C style again. 
  64.  */  
  65.  // 定义枚举类型  
  66. enum Operation {  
  67.   ADD = 1,  
  68.   SUBTRACT = 2,  
  69.   MULTIPLY = 3,  
  70.   DIVIDE = 4  
  71. }  
  72. /** 
  73.  * Structs are the basic complex data structures. They are comprised of fields 
  74.  * which each have an integer identifier, a type, a symbolic name, and an 
  75.  * optional default value. 
  76.  * 
  77.  * Fields can be declared "optional", which ensures they will not be included 
  78.  * in the serialized output if they aren't set.  Note that this requires some 
  79.  * manual management in some languages. 
  80.  */  
  81. struct Work {  
  82.   1: i32 num1 = 0,  
  83.   2: i32 num2,  
  84.   3: Operation op,          
  85.   4: optional string comment, //这里的optional字段类型表示如果这个字段的值没有被赋值,它就不会被序列化输出  
  86. }  
  87. /** 
  88.  * Structs can also be exceptions, if they are nasty. 
  89.  */  
  90.  // 这里定义了一些异常  
  91. exception InvalidOperation {  
  92.   1: i32 what,  
  93.   2: string why  
  94. }  
  95. /** 
  96.  * Ahh, now onto the cool part, defining a service. Services just need a name 
  97.  * and can optionally inherit from another service using the extends keyword. 
  98.  */  
  99.  // 这里是定义服务,它继承了shared的服务  
  100. service Calculator extends shared.SharedService {  
  101.   /** 
  102.    * A method definition looks like C code. It has a return type, arguments, 
  103.    * and optionally a list of exceptions that it may throw. Note that argument 
  104.    * lists and exception lists are specified using the exact same syntax as 
  105.    * field lists in struct or exception definitions. 
  106.    */  
  107.    void ping(),  
  108.    i32 add(1:i32 num1, 2:i32 num2),  
  109.    i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),  
  110.    /** 
  111.     * This method has a oneway modifier. That means the client only makes 
  112.     * a request and does not listen for any response at all. Oneway methods 
  113.     * must be void. 
  114.     */  
  115.    oneway void zip()  
  116. }  
 

 

4.2 服务端与客户端代码的分析

   4.2.1 c++服务端

   在tutorial/cpp目录中的CppServer.cpp是它的服务代码,主要分成两部分,

   一部分是main方法用于做一些初始化与服务的启动,第二部分对于IDL中定义的接口的实现

 

[c-sharp]  view plain copy
  1.   int main(int argc, char **argv) {  
  2. // 定义了RPC的协议工厂,这里使用了二进制协议,你不可以使用别的协议,如JSON,Compact等  
  3. shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());  
  4. // 这里生成用户实现的CalculatorHandler服务,再把其帮定到一个Processor上去,它主要用于处理协议的输入与输出流  
  5. shared_ptr<CalculatorHandler> handler(new CalculatorHandler());  
  6. shared_ptr<TProcessor> processor(new CalculatorProcessor(handler));  
  7. // 生成一个传输通道,这里使用了Socket方式  
  8. shared_ptr<TServerTransport> serverTransport(new TServerSocket(9090));  
  9. // 生成一个传输工厂,主要用于把上面的transport转换成一个新的应用层传输通道  
  10. shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());  
  11. // 生成一个简单的服务端,这是一个单线程的服务端   
  12. TSimpleServer server(processor,  
  13.                       serverTransport,  
  14.                       transportFactory,  
  15.                       protocolFactory);  
  16. // 你也可以生成一个多线程的服务端,就是对其加入线程池。但它现在还不支持进程池,但可能会在0.7版本中进行支持。  
  17.  /** 
  18.   * Or you could do one of these 
  19.  shared_ptr<ThreadManager> threadManager = 
  20.    ThreadManager::newSimpleThreadManager(workerCount); 
  21.  shared_ptr<PosixThreadFactory> threadFactory = 
  22.    shared_ptr<PosixThreadFactory>(new PosixThreadFactory()); 
  23.  threadManager->threadFactory(threadFactory); 
  24.  threadManager->start(); 
  25.  TThreadPoolServer server(processor, 
  26.                           serverTransport, 
  27.                           transportFactory, 
  28.                           protocolFactory, 
  29.                           threadManager); 
  30.  TThreadedServer server(processor, 
  31.                         serverTransport, 
  32.                         transportFactory, 
  33.                         protocolFactory); 
  34.  */  
  35.  printf("Starting the server.../n");  
  36.  server.serve();   // 启动服务  
  37.  printf("done./n");  
  38.  return 0;  
  39. }  
 

 

 

另一部分如下:

[c-sharp]  view plain copy
  1. // 这一部分主要是实现接口类,用于提供给相应的服务使用。  
  2. class CalculatorHandler : public CalculatorIf {  
  3. public:  
  4.  CalculatorHandler() {}  
  5.  void ping() {  
  6.    printf("ping()/n");  
  7.  }  
  8.  int32_t add(const int32_t n1, const int32_t n2) {  
  9.    ...  
  10.  }  
  11.  int32_t calculate(const int32_t logid, const Work &work) {  
  12.  ...  
  13.  }  
  14.  void getStruct(SharedStruct &ret, const int32_t logid) {  
  15.  ...  
  16.  }  
  17.  void zip() {  
  18.    printf("zip()/n");  
  19.  }  
  20. protected:  
  21.  map<int32_t, SharedStruct> log;  
  22. };  
 

4.2.2 c++客户端

[c-sharp]  view plain copy
  1. int main(int argc, char** argv) {  
  2.  // 生成一个Socket连接到服务端  
  3.  shared_ptr<TTransport> socket(new TSocket("localhost", 9090));  
  4.  // 对Socket通道加入缓冲功能  
  5.  shared_ptr<TTransport> transport(new TBufferedTransport(socket));  
  6.  // 生成相应的二进制协议,这个要和服务端一致,不然会出现协议版本不对的错误  
  7.  shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));  
  8.  // 生成客户端的服务对象  
  9.  CalculatorClient client(protocol);  
  10.  try {  
  11.    transport->open(); // 加开服务  
  12.    // 调用事先定义好的服务接口  
  13.    client.ping();  
  14.    printf("ping()/n");  
  15.    int32_t sum = client.add(1,1);  
  16.    printf("1+1=%d/n", sum);  
  17.    Work work;  
  18.    work.op = Operation::DIVIDE;  
  19.    work.num1 = 1;  
  20.    work.num2 = 0;  
  21.    try {  
  22.      int32_t quotient = client.calculate(1, work);  
  23.      printf("Whoa? We can divide by zero!/n");  
  24.    } catch (InvalidOperation &io) {  
  25.      printf("InvalidOperation: %s/n", io.why.c_str());  
  26.    }  
  27.    work.op = Operation::SUBTRACT;  
  28.    work.num1 = 15;  
  29.    work.num2 = 10;  
  30.    int32_t diff = client.calculate(1, work);  
  31.    printf("15-10=%d/n", diff);  
  32.    // Note that C++ uses return by reference for complex types to avoid  
  33.    // costly copy construction  
  34.    SharedStruct ss;  
  35.    client.getStruct(ss, 1);  
  36.    printf("Check log: %s/n", ss.value.c_str());  
  37.    // 关闭服务  
  38.    transport->close();  
  39.  } catch (TException &tx) {  
  40.    printf("ERROR: %s/n", tx.what());  
  41.  }  
  42. }  
 

4.2.3 其它代码的实现

在tutorial目录中有其它代码的例子,如erl,java,python,perl,ruby等。

 

5 参考

1. http://incubator.apache.org/thrift/

2. http://incubator.apache.org/thrift/static/thrift-20070401.pdf

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值