thrift

来源:互联网 发布:windows桌面图片草原 编辑:程序博客网 时间:2024/05/03 08:55

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 plaincopy
  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 plaincopy
  1. thrift -version  

3. 一个简单的例子

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

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

 

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

 

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

 

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

 

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

 

[c-sharp] view plaincopy
  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文件,内容如下:

<strong><span style="font-size:14px;">    shared.thrift      ---------------      **       * This Thrift file can be included by other Thrift files that want to share       * these definitions.       */      namespace cpp shared      namespace java shared      namespace perl shared      // 这里定义了一个结构体,没有定义方法,对应于生成的代码在gen-cpp中的shared_types.h中,其中有一个class叫SharedStruct,      // 有没有看到其中有两个方法叫read和write,这就是用来对其进行序列化与把序列化的方法.      // 对了,其中的i32是Thrift IDL中定义的变量类型,对应于c++语言中的int32_t      struct SharedStruct {            1: i32 key        2: string value      }      // 这里定义的一个服务,它语义上类似于面向对象中的定义一个接口,thrift的编译器会对其产生一套实现其接口的客户端与服务端方法      // 服务的一般定义格式如下      // service <name>      // <returntype> <name>(<arguments>)      // [ throws (<exceptions>)]      //   ...      // }      service SharedService {        SharedStruct getStruct(1: i32 key)      }      tutorial.thrift      ----------------      /**      * 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      */       // 这个IDL包含了另一个IDL,也就是说另一个IDL中的对象与服务对其时可见的      include "shared.thrift"      /**      * Thrift files can namespace, package, or prefix their output in various      * target languages.      */       // 这里定义了一些语言的namespace空间      namespace cpp tutorial      namespace java tutorial      namespace php tutorial      namespace perl 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 = 9853      const 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.      */       // 定义枚举类型      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, //这里的optional字段类型表示如果这个字段的值没有被赋值,它就不会被序列化输出      }      /**      * 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.      */       // 这里是定义服务,它继承了shared的服务      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.        */         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 a oneway modifier. That means the client only makes         * a request and does not listen for any response at all. Oneway methods         * must be void.         */         oneway void zip()      }  </span></strong>
<strong><span style="font-size:14px;"> enum    泛型名 struct  类名</span></strong>
<strong><span style="font-size:14px;"> service 接口名</span></strong>
格式如上所示。

2.1 Types

Thrift类型系统包括预定义基本类型,用户自定义结构体,容器类型,异常和服务定义

(1) 基本类型

binary: 字节数组(byte array)----------------------------------------byte[ ]

bool:布尔类型(true or value),占一个字节------------booleanbyte:有符号字节------------------------------------Bytei16:16位有符号整型----------------------------------shorti32:32位有符号整型----------------------------------int,Integeri64:64位有符号整型----------------------------------long,或Datedouble:64位浮点数----------------------------------Doublestring:未知编码或者二进制的字符串-------------------String
list<t1>: List<t1>
 
set<t1>: Set<t1>
 
map<t1,t2>: Map<t1, t2>

注意,thrift不支持无符号整型,因为很多目标语言不存在无符号整型(如java)。

    相关例子:
enumTweetType {
 
TWEET,      //a
 
RETWEET = 2,//b
 
DM = 0xa, //c
 
REPLY
 
}       //d
 
structTweet {
 
1: required i32 userId;
 
2: required string userName;
 
3: required string text;
 
4: optional Location loc;
 
5: optional TweetType tweetType = TweetType.TWEET// e
 
16: optional string language ="english"
 
}

说明:

a.  编译器默认从0开始赋值

b.  可以赋予某个常量某个整数

c.  允许常量是十六进制整数

d.  末尾没有逗号

e.  给常量赋缺省值时,使用常量的全称

注意,不同于protocol buffer,thrift不支持枚举类嵌套,枚举常量必须是32位的正整数

2.2   文件包含

Thrift允许thrift文件包含,用户需要使用thrift文件名作为前缀访问被包含的对象,如:

1
2
3
4
5
6
7
8
9
include"tweet.thrift"          // a
 
...
 
structTweetSearchResult {
 
1: list<tweet.Tweet> tweets;// b
 
}

说明:

a.  thrift文件名要用双引号包含,末尾没有逗号或者分号

b.  注意tweet前缀

2.3   定义结构体

结构体由一系列域组成,每个域有唯一整数标识符,类型,名字和可选的缺省参数组成。如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
structTweet {
 
1: required i32 userId;                 // a
 
2: required string userName;            // b
 
3: required string text;
 
4: optional Location loc;               // c
 
16: optional string language ="english"// d
 
}
 
structLocation {                           // e
 
1: required double latitude;
 
2: required double longitude;
 
}

说明:

a.  每个域有一个唯一的,正整数标识符

b.  每个域可以标识为required或者optional(也可以不注明)

c.  结构体可以包含其他结构体

d.  域可以有缺省值

e.  一个thrift中可定义多个结构体,并存在引用关系

规范的struct定义中的每个域均会使用required或者optional关键字进行标识。如果required标识的域没有赋值,thrift将给予提示。如果optional标识的域没有赋值,该域将不会被序列化传输。如果某个optional标识域有缺省值而用户没有重新赋值,则该域的值一直为缺省值。

与service不同,结构体不支持继承,即,一个结构体不能继承另一个结构体。

2.4   定义服务

在流行的序列化/反序列化框架(如protocol buffer)中,thrift是少有的提供多语言间RPC服务的框架。

Thrift编译器会根据选择的目标语言为server产生服务接口代码,为client产生桩代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//“Twitter”与“{”之间需要有空格!!!
service Twitter {
 
// 方法定义方式类似于C语言中的方式,它有一个返回值,一系列参数和可选的异常
 
// 列表. 注意,参数列表和异常列表定义方式与结构体中域定义方式一致.
 
void ping(),                                    // a
 
bool postTweet(1:Tweet tweet);                  // b
 
TweetSearchResult searchTweets(1:string query);// c
 
// ”oneway”标识符表示client发出请求后不必等待回复(非阻塞)直接进行下面的操作,
 
// ”oneway”方法的返回值必须是void
 
oneway voidzip()                              // d
 
}

说明:

a. 函数定义可以使用逗号或者分号标识结束

b. 参数可以是基本类型或者结构体,参数是只读的(const),不可以作为返回值!!!

c. 返回值可以是基本类型或者结构体

d. 返回值可以是void

注意,函数中参数列表的定义方式与struct完全一样

Service支持继承,一个service可使用extends关键字继承另一个service

在cmd下运行:thrift -o  ../src/mian/java  -out  ../src/mian/java  --gen  java:fullcamel   IReward.thrift

1 0