Thrift 简介

 

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

你可能感兴趣的:(Thrift 简介)