Thrift是一个跨语言服务部署框架,最初由Facebook于2007年开发,后于2008年进入Apache孵化器(Apache Incubator)。
类似于SOAP,COM 和CORBA,Thrift通过定义一个中间定义语言和Thrift代码生成工具,生成指定语言的代码。目前,Thrift支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml的代码生成。
简单分析其机理,Thrift就是实现C/S模式,通过代码生成工具将接口定义文件生成服务器端和客户端代码(可以为不同语言),从而实现服务端和客户端跨语言的支持。
更多的内容可以参看下面的链接
http://thrift.apache.org/
下面贴一些使用的例子,更便于理解。
1、首先安装thrift,这个就不多说了
./configure
make
makeinstall
2、编写.thrift文件,告诉Thrift你需要怎样的数据结构以及服务形式
#RTDCCmd.thrift
struct Rusult {
1: i32 status,
2: string output
}
service RTDCCommand{
Rusult osCmd(1: string cmd)
oneway void osCmdAsync(1: string cmd)
}
文件里定义了两个东西,一个是数据结构Rusult,类似于一个结构体,由两个元素组成,一个整型,一个字符型;另一个是服务RTDCCommand,里面定义了两个接口,一个是osCmd,用于执行一个操作系统命令,一个osCmdAsync,用于执行异步命令的调用(可以用于RPC场景)。
3、生成thrift相应的包、模块,下面分别生成PYTHON和PERL的
thrift -r --gen py RTDCCmd.thrift
thrift -r --gen perl RTDCCmd.thrift
执行完成以后,目录下分别会生成gen-py 和gen-perl两个文件夹,里面分别是需要用到的一些包、模块。
4、仅仅靠thrift自动生成的那些东西当然还不够,前面我们定义了一些接口,接下来我们需要对其进行实现。我把自己写的几个程序代码都贴上吧,便于理解
#RTDCCommandHandler.py
#!/bin/env python
from RTDCCmd.ttypes import *
from RTDCCmd import RTDCCommand
import commands
import os
import sys
class RTDCCommandHandler(RTDCCommand.Iface):
def __init__(self):
#RTDCCommand.Iface.__init__(self)
pass
def osCmd(self,cmd):
ret = commands.getstatusoutput(cmd)
result = Rusult(ret[0],ret[1])
return result
def osCmdAsync(self,cmd):
commands.getstatusoutput(cmd)
继承RTDCCommand.Iface,对其接口进行实现。
#RTDCServer.py
#!/bin/env python
from thrift.server.TServer import TServer
from thrift.server.TServer import TSimpleServer
from thrift.server.TServer import TThreadedServer
from thrift.transport.TSocket import TServerSocket
from thrift.transport.TTransport import *
from RTDCCommandHandler import RTDCCommandHandler
from RTDCCmd import *
if __name__ == '__main__':
handler = RTDCCommandHandler()
processor = RTDCCommand.Processor(handler)
serverTransport = TServerSocket(9091)
server = TThreadedServer(processor,serverTransport)
print "start server......"
server.serve()
这个其实就是一个服务进程,client端连接server,进行相关请求。
#RTDCClient.py
#!/bin/env python
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from RTDCCmd.RTDCCommand import Client
from RTDCCmd.ttypes import *
class RTDCClient():
#static member
port = 9091
#constructor
def __init__():
pass
@staticmethod
def remoteOSCmd(host,cmd):
ret=[1,'err']
try:
transport = TSocket.TSocket(host,RTDCClient.port)
transport = TTransport.TBufferedTransport(transport)
#wrap in a protocol
protocol = TBinaryProtocol.TBinaryProtocol(transport)
client = Client(protocol)
#open transport
transport.open()
result = client.osCmd(cmd)
ret = [result.status,result.output]
except:
s=sys.exc_info()
print str(s[1]) + ' on line ' + str(s[2].tb_lineno)
finally:
if transport:
transport.close()
return ret
@staticmethod
def remoteOSCmdAsync(host,cmd):
try:
transport = TSocket.TSocket(host,RTDCClient.port)
transport = TTransport.TBufferedTransport(transport)
#wrap in a protocol
protocol = TBinaryProtocol.TBinaryProtocol(transport)
client = Client(protocol)
#open transport
transport.open()
client.osCmdAsync(cmd)
except:
s=sys.exc_info()
print str(s[1]) + ' on line ' + str(s[2].tb_lineno)
finally:
if transport:
transport.close()
这个是CLIENT端代码的实现,在其他程序中只要引用CLINET端里面的两个静态方法就可以实现远程调用的功能了。
下面给个示例程序,功能很简单,就是远程执行一个cat命令把testfile文件的内容打印出来,并返回。最后在程序中把程序的运行状态和输出结果分别print到标准输出上
#1.py
#!/bin/env python
from RTDCClient import RTDCClient
import time
ISOTIMEFORMAT='%Y-%m-%d %X'
ret = RTDCClient.remoteOSCmd("localhost","cat /home/gpadmin1/joe.wangh/thrift/test/gen-py/testfile")
print time.strftime( ISOTIMEFORMAT, time.localtime() )
print ret[0]
print ret[1]
首先运行server进程
nohup python RTDCServer.py &
然后运行示例程序
[gpadmin1@hadoop5 gen-py]$ python 1.py
2011-05-24 14:40:45
0
haha
hehe
前面的那一堆东西,全是用PYTHON写的,没实现跨语言调用,不给力,总觉得没发挥Thrift价值,呵呵,下面用PERL来实现一个CLIENT试试。
#RTDCClient.pl
#!/usr/bin/perl
use strict; #declare using perl strict syntax
use Thrift;
use Thrift::Socket;
use Thrift::FramedTransport;
use Thrift::BinaryProtocol;
use Thrift::BufferedTransport;
use Thrift::Constants;
use Thrift::RTDCCommand;
use Thrift::Types;
package RTDCClient;
my $port = 1987;
my $host = "";
my $cmd = "";
my $result = Rusult->new(undef,undef);
#connect to db
sub remoteOSCmd
{
$host = @_[0];
$cmd = @_[1];
my $socket = Thrift::Socket->new($host,$port);
$socket->setRecvTimeout(1000000000);
my $transport = Thrift::BufferedTransport->new($socket);
my $protocol = Thrift::BinaryProtocol->new($transport);
my $client = RTDCCommandClient->new($protocol);
eval {$transport->open()};
if($@)
{
my $ex = $@;
die "error when transport open: $@".$ex->{message}."/n";
}
#$result = RTDCCommandClient->osCmd($client,$cmd);
$result = $client->osCmd($cmd);
return $result;
}
sub remoteOSCmdAsync
{
$host = @_[0];
$cmd = @_[1];
my $socket = Thrift::Socket->new($host,$port);
$socket->setRecvTimeout(1000000000);
my $transport = Thrift::BufferedTransport->new($socket);
my $protocol = Thrift::BinaryProtocol->new($transport);
my $client = RTDCCommandClient->new($protocol);
eval {$transport->open()};
if($@)
{
my $ex = $@;
die "error when transport open: $@".$ex->{message}."/n";
}
#$result = RTDCCommandClient->osCmd($client,$cmd);
$client->osCmdAsync($cmd);
}
1; #terminate the package with the required 1
示例程序如下
#1.pl
use strict;
use RTDCClient;
RTDCClient::remoteOSCmdAsync("localhost","sleep 10;touch /home/dwapp/joe.wangh/gen-py/testfile1");
该程序的功能是实现一个远程异步调用,在程序中我故意先sleep 10,你会看到在客户端程序很快就返回了。可是在服务端,过10秒钟以后才会生成一个testfile1文件。
差不多就写这些吧,在我学习Thrift的过程中比较费事的时有时环境不正确,比如说PYTHONPATH或者PERL5LIB,或者你机器上其他一些库没有装,其他的倒还好。
转自:http://blog.csdn.net/wh62592855/article/details/6442344