引用网上对thrift的介绍:
Thrift源于大名鼎鼎的facebook之手,在2007年facebook提交Apache基金会将Thrift作为一个开源项目, 对于当时的facebook来说创造thrift是为了解决facebook系统中各系统间大数据量的传 输通信以及系统之间语言环境不同需要跨平台的特性。 所以thrift可以支持多种程序语言,例如: C++, C#, Cocoa, Erlang, Haskell, Java, Ocami, Perl, PHP, Python, Ruby, Smalltalk. 在多种不同的语言之间通信thrift可以作为二进制的高性能的通讯中间件,支持数据(对象)序列化和多种类型的RPC服务。 Thrift适用于程序对程 序静态的数据交换,需要先确定好他的数据结构,他是完全静态化的,当数据结构发生变化时,必须重新编辑IDL文件, 代码生成,再编译载入的流程,跟其他IDL工具相比较可以视为是Thrift的弱项,Thrift适用于搭建大型数据交换及存储的通用工具, 对于大型系统中的内部数据传输相对于JSON和xml无论在性能、传输大小上有明显的优势。
主要根据这里的教程:
http://www.thrift.pl/Thrift-tutorial-our-own-hello-world.html
这里面的有几处错误,可能是老版本的thrift。
首先下载安装thrift最新版本。编译安装步骤:
sudo apt-get install libboost-dev libboost-test-dev libboost-program-options-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev wget -c https://dist.apache.org/repos/dist/release/thrift/0.8.0/thrift-0.8.0.tar.gz tar -zvxf thrift-0.8.0.tar.gz cd thrift-0.8.0 ./configure make sudo make install
安装好后,安装相应的python库,不然在运行python实例的时候会提示“ImportError: No module named Thrift”错误。
cd thrift-0.8.0/lib/py sudo python setup.py install
ok,现在我们来生成一个thrift文件,定义一个数据类型与方法,在thrift-0.8.0文件夹下面创建hello.thrift文件:
namespace php hello enum SexType { MALE = 1, FEMALE = 2 } struct User { 1: string firstname, 2: string lastname, 3: i32 user_id, 4: SexType sex, 5: bool active = false, 6: optional string description } exception InvalidValueException { 1: i32 error_code, 2: string error_msg } service UserManager { void ping(), i32 add_user(1:User u) throws (1: InvalidValueException e), User get_user(1:i32 uid) throws (1: InvalidValueException e), oneway void clear_list() }
首先我们定义了一个在php代码下的命名空间,namespace php hello。这样在生成相应的php代码后,php类名前加有hello_的前缀。
然后定义了一个性别的枚举类型SexType。
再下面就是结构体User,在定义字段的时候,每个字段前必须加一个序号,后面根数据类型。可以给字段设置默认值,如bool active = false。默认情况下所有字段都为必需,要使其为可选,可加optional修饰符。
exception InvalidValueException 定义了一个异常,当传递的参数不合法时,就抛出此异常。
接下来定义了一个服务类 UserManager,下面是一些方法。格式根我们编程定义的类似,很容易看懂。
最后一个方法加了oneway,表名在客户端调用此方法时,不用等待服务端返回就立马结束。
下面我们用thrift命名来生成相应的代码:
thrift -r --gen php hello.thrift thrift -r --gen py hello.thrift
这时候,在目录下面出现两个目录,gen-py和gen-php,分别为php与python的代码。
我们用python来写服务端,新建python_server.py:
#!/usr/bin/env python import sys sys.path.append('./gen-py') from hello import UserManager from hello.ttypes import * from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from thrift.server import TServer users = [] class UserManagerHandler: def __init__(self): pass #self.log = {} def ping(self): print 'ping()' def add_user(self, user): if user.firstname == None: raise InvalidValueException(1,'no firstname exception') if user.lastname == None: raise InvalidValueException(2, 'no lastname exception') if user.user_id <= 0: raise InvalidValueException(3, 'wrong user_id') if user.sex != SexType.MALE and user.sex != SexType.FEMALE: raise InvalidValueException(4, 'wrong sex id') print 'Processing user '+user.firstname+' '+user.lastname users.append(user) print users return True def get_user(self, user_id): if user_id < 0: raise InvalidValueException(5, 'wrong id') return users[user_id] def clear_list(self): print 'Clearing list' print users del users [:] print users handler = UserManagerHandler() processor = UserManager.Processor(handler) transport = TSocket.TServerSocket(port=9090) tfactory = TTransport.TBufferedTransportFactory() pfactory = TBinaryProtocol.TBinaryProtocolFactory() server = TServer.TSimpleServer(processor, transport, tfactory, pfactory) # You could do one of these for a multithreaded server #server = TServer.TThreadedServer(processor, transport, tfactory, pfactory) #server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory) print 'Starting the server...' server.serve() print 'done.'
sys.path.append(‘./gen-py’) 这句话是把我们之前用thrift生成的python类代码引用进来。
然后我们运行此服务端:
chmod +x ./python_server.py ./python_server.py
接下来我们用php来实现客户端,当执行php页面后,php去连接python的服务端,调用相应的方法等。
在apache网站根目录下面,我们创建一个文件夹来放示例php代码。
cd ~/www/ mkdir thrift-php cd thrift-php cp -r ~/thrift-0.8.0/lib/php/src/ . #要用到thrift的php类库 cd src mkdir packages cd packages cp -r ~/thrift-0.8.0/gen-php/hello/ . #将我们之前生成的hello的php部分代码复制过来
然后我们在thrift-php目录下面新建hello.php文件:
<?php $GLOBALS['THRIFT_ROOT'] = 'src'; require_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php'; require_once $GLOBALS['THRIFT_ROOT'].'/protocol/TBinaryProtocol.php'; require_once $GLOBALS['THRIFT_ROOT'].'/transport/TSocket.php'; require_once $GLOBALS['THRIFT_ROOT'].'/transport/THttpClient.php'; require_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php'; require_once $GLOBALS['THRIFT_ROOT'].'/packages/hello/UserManager.php'; try { $socket = new TSocket('localhost', 9090); $transport = new TBufferedTransport($socket, 1024, 1024); $protocol = new TBinaryProtocol($transport); $client = new hello_UserManagerClient($protocol); $transport->open(); $client->ping(); $u = new hello_User(); $u->user_id = 1; $u->firstname = 'John'; $u->lastname = 'Smith'; $u->sex = SexType::MALE; if ($client->add_user($u)) { echo 'user added succesfully</br>'; } var_dump($client->get_user(0)); $client->clear_list(); $u2 = new hello_User(); $client->add_user($u2); } catch (hello_InvalidValueException $e) { echo $e->error_msg.'<br/>'; } ?>
现在就可以在浏览器中运行我们的php客户端了,打开 http://127.0.0.1/thrift-php/hello.php,显示:
user added succesfully</br>object(hello_User)#7 (6) { ["firstname"]=> string(4) "John" ["lastname"]=> string(5) "Smith" ["user_id"]=> int(1) ["sex"]=> int(1) ["active"]=> bool(false) ["description"]=> NULL } no firstname exception
在python的服务器输出:
Starting the server... ping() Processing user John Smith [User(user_id=1, description=None, firstname='John', lastname='Smith', sex=1, active=False)] Clearing list [User(user_id=1, description=None, firstname='John', lastname='Smith', sex=1, active=False)] []
ok,最基本的hello例子就完成了。
在这里还能找到更加丰富的例子:
https://github.com/apache/thrift/tree/trunk/tutorial