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 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),占一个字节------------boolean

byte:有符号字节------------------------------------Byte

i16:16位有符号整型----------------------------------short

i32:32位有符号整型----------------------------------int,Integer

i64:64位有符号整型----------------------------------long,或Date

double:64位浮点数----------------------------------Double

string:未知编码或者二进制的字符串-------------------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
struct Tweet {
 
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
 
}
 
struct Location {                            // 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 void zip()                               // 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值