Apache Thrift 支持異構(gòu)語言之間的調(diào)用

前言

之前介紹了Apache Thrift的快速入門婶恼,我們使用java作為客戶端廊营,使用java作為服務(wù)器端Apache Thrift及其入門哼凯,我們知道RPC框架的一個基本特征就是支持異構(gòu)語言之間的調(diào)用锌妻,本篇博客介紹異構(gòu)語言之間的調(diào)用。

Apache Thrift allows you to define data types and service interfaces in a simple definition file. Taking that file as input, the compiler generates code to be used to easily build RPC clients and servers that communicate seamlessly across programming languages. Instead of writing a load of boilerplate code to serialize and transport your objects and invoke remote methods, you can get right down to business.

Apache Thrift可以在文件中定義數(shù)據(jù)類型和服務(wù)接口沸呐。編譯器根據(jù)idl(接口定義文件)文件可以生成消息傳輸類型的Message對象醇王,也生成RPC語言網(wǎng)絡(luò)傳輸?shù)拇a,使得我們可以跨語言跨平臺的調(diào)用服務(wù)垂谢。

Python作為Client厦画,Java作為Server

idl文件(接口描述文件),定義了結(jié)構(gòu)體(struct)滥朱,異常(exception)和服務(wù)(service):

namespace java thrift.generated
namespace py py.thrift.generated

typedef i16 short
typedef i32 int
typedef i64 long
typedef bool boolean
typedef string String

struct Person{
    1: optional String username,
    2: optional int age,
    3: optional boolean married
}

exception DataException{
    1: optional String message,
    2: optional String callStack,
    3: optional String date
}

service PersonService{
    Person getPersonByUsername(1: required String username) throws (1: DataException dateException),

    void savePerson(1: required Person person) throws (1: DataException dataException)
}

使用thrift編譯器生成編譯文件

thrift --gen java src/thrift/data.thrift
thrift --gen py src/thrift/data.thrift 
java生成的代碼
python生成的代碼

加入Thrift依賴,pom文件:

<dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libthrift</artifactId>
    <version>0.10.0</version>
</dependency>

python依賴要自己編譯一下官方的包下載地址,到解壓后的lib目錄下進(jìn)入py目錄下進(jìn)行編譯得到Apache Thrift 項目中所使用的python庫(lib目錄下有Apache Thrift 支持的各種語言的庫):

?  py  cd /Users/naeshihiroshi/study/studySummarize/netty/thrift-0.10.0/lib/py
?  py  ll

安裝python相應(yīng)的包

?  py  sudo python setup.py install

生成的依賴位于/Library/Python/2.7/site-packages/

?  py cd /Library/Python/2.7/site-packages/
?  site-packages ll
total 480
-rwxr-xr-x  1 root  wheel   157B  7 31  2016 Extras.pth
-rw-r--r--  1 root  wheel   119B  7 31  2016 README
-rw-r--r--  1 root  wheel   263B  6 17 19:31 easy-install.pth
drwxr-xr-x  6 root  wheel   204B  6 17 19:31 six-1.10.0-py2.7.egg
-rw-r--r--  1 root  wheel   235K  6 17 19:31 thrift-0.10.0-py2.7-macosx-10.12-intel.egg

Python作為Client力试,Java作為Server

Java Server

編寫java服務(wù)器端實現(xiàn)代碼(一般服務(wù)器端要編寫一個業(yè)務(wù)代碼實現(xiàn)供客戶端調(diào)用徙邻,還有一個服務(wù)代碼):

public class PersonServiceImpl implements PersonService.Iface{

    @Override
    public Person getPersonByUsername(String username) throws DataException, TException {
        System.out.println("Got client Param:" + username);

        Person person = new Person();
        person.setUsername(username);
        person.setAge(32);
        person.setMarried(true);

        return person;
    }

    @Override
    public void savePerson(Person person) throws DataException, TException {
        System.out.println("Got Client Param: ");

        System.out.println(person.getUsername());
        System.out.println(person.getAge());
        System.out.println(person.isMarried());
    }
}

服務(wù)端:

public class ThriftServer {
    public static void main(String[] args) throws Exception{

        TNonblockingServerSocket socket = new TNonblockingServerSocket(8899);
        THsHaServer.Args arg = new THsHaServer.Args(socket).minWorkerThreads(2).maxWorkerThreads(4);
        PersonService.Processor<PersonServiceImpl> processor = new PersonService.Processor<>(new PersonServiceImpl());

        //表示協(xié)議層次(壓縮協(xié)議)
        arg.protocolFactory(new TCompactProtocol.Factory());
        //表示傳輸層次
        arg.transportFactory(new TFramedTransport.Factory());
        arg.processorFactory(new TProcessorFactory(processor));

        //半同步半異步的server
        TServer server = new THsHaServer(arg);

        System.out.println("Thrift Server started!");

        server.serve();
    }
}

python的客戶端:

將上面自動生成的代碼拷貝到python項目中,

python生成的代碼

py_client.py代碼:

# _*_ coding:utf-8 _*_
__author__ = '作者'

# 導(dǎo)入thrift的包
from py.thrift.generated import PersonService
from py.thrift.generated import ttypes

from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TCompactProtocol
import sys

# 解決中文編碼問題
reload(sys)
sys.setdefaultencoding('utf8')

try:
    tSocket = TSocket.TSocket('localhost',8899)
    tSocket.setTimeout(600)

    # 與java服務(wù)器一樣使用相同的傳輸協(xié)議畸裳,數(shù)據(jù)的傳輸方式缰犁,服務(wù)模型
    transport = TTransport.TFramedTransport(tSocket)
    protocal = TCompactProtocol.TCompactProtocol(transport)
    client = PersonService.Client(protocal)

    transport.open()

    # 調(diào)用getPersonByUsername方法返回一個person對象
    person = client.getPersonByUsername("張三")

    print person.username
    print  person.age
    print person.married

    print '--------------'

    newPerson = ttypes.Person()
    newPerson.username ='lisi'
    newPerson.age = 30
    newPerson.married =True

    client.savePerson(newPerson)

    transport.close()


except Thrift.TException,tx:
    print '%s' % tx.message

啟動java服務(wù)器端和python客戶端,
python客戶端打硬篮:

張三
32
True
--------------

java服務(wù)器端的打印結(jié)果:

Got client Param:張三
Got Client Param: 
lisi
30
true

java客戶端帅容,python服務(wù)器端

服務(wù)器端要編寫服務(wù)接口的實現(xiàn)和服務(wù)器端代碼:

# _*_ coding:utf-8 _*_
__author__ = '作者'

# 導(dǎo)入包
from py.thrift.generated import ttypes

#處理器
class PersonHandler :

    def getPersonByUsername(self,username):
        print "Got client param: "+username

        person = ttypes.Person()
        person.username = username
        person.age = 20
        person.married = False

        return person

    def savePerson(self,person):
        print "Got client param: "

        print person.username
        print person.age
        print person.married

python 服務(wù)器端代碼

# _*_ coding:utf-8 _*_
__author__ = '作者'

# 導(dǎo)入包
from py.thrift.generated import PersonService
from PersonHandler import PersonHandler

from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TCompactProtocol
from thrift.server import TServer

try:
    personHandler = PersonHandler()
    processor = PersonService.Processor(personHandler)

    serverSocket = TSocket.TServerSocket(port=8899)
    # 傳輸方式工廠
    transportFactory = TTransport.TFramedTransportFactory()
    # 協(xié)議工廠
    protocolFactory = TCompactProtocol.TCompactProtocolFactory()

    server = TServer.TSimpleServer(processor,serverSocket,transportFactory,protocolFactory)
    server.serve()

except Thrift.TException, ex:
    print '%s' % ex.message

java客戶端:

import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFastFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import thrift.generated.Person;
import thrift.generated.PersonService;

//服務(wù)端的協(xié)議和客戶端的協(xié)議要一致
public class ThriftClient {
    public static void main(String[] args) {

        TTransport tTransport = new TFastFramedTransport(new TSocket("localhost",8899),600);
        TProtocol tProtocol = new TCompactProtocol(tTransport);
        PersonService.Client client = new PersonService.Client(tProtocol);

        try{
            tTransport.open();

            Person person = client.getPersonByUsername("張三");

            System.out.println(person.getUsername());
            System.out.println(person.getAge());
            System.out.println(person.isMarried());

            System.out.println("............");

            Person person2 = new Person();

            person2.setUsername("李四");
            person2.setAge(30);
            person2.setMarried(true);

            client.savePerson(person2);
        }catch (Exception ex){
            throw new  RuntimeException(ex.getMessage(),ex);
        }finally {
            tTransport.close();
        }
    }
}

啟動python服務(wù)器端和java客戶端,python服務(wù)器端控制臺打游樯恕:

Got client param: 張三
Got client param: 
李四
30
True

java客戶端代碼:

Received 1
張三
20
false
............
Received 2

總結(jié)

比較一下Apache thrift與Protobuf之間的區(qū)別:

單純的只看Protobuf本身并徘,Protobuf只是一個序列化與反序列化的一個庫而已,而Protobuf并沒有提供網(wǎng)絡(luò)傳輸載體扰魂,我們之前的netty與Protobuf結(jié)合就是使用netty作為網(wǎng)絡(luò)傳輸組件(也就是說netty作為RPC框架中的Transport(傳輸方式)組件)麦乞,而Protobuf作為Protocal(傳輸協(xié)議)組件。而Apache thrift本身就是一個跨語言的RPC框架劝评,可以直接通過thrift就可以客戶端與服務(wù)器之間的通信(通過idl文件生成的代碼即提供了傳輸協(xié)議姐直,也提供了網(wǎng)絡(luò)傳輸方式)〗螅基于Protobuf沒有提供網(wǎng)絡(luò)傳輸組件声畏,google又推出了自己的RPC框架GRPC,GRPC是基于Protobuf 3.0版本姻成,基于.proto文件不僅能生成序列化反序列化程序代碼插龄,也可以生成傳輸層次的代碼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末佣渴,一起剝皮案震驚了整個濱河市辫狼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辛润,老刑警劉巖膨处,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件见秤,死亡現(xiàn)場離奇詭異,居然都是意外死亡真椿,警方通過查閱死者的電腦和手機(jī)鹃答,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來突硝,“玉大人测摔,你說我怎么就攤上這事〗馇。” “怎么了锋八?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長护盈。 經(jīng)常有香客問我挟纱,道長,這世上最難降的妖魔是什么腐宋? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任紊服,我火速辦了婚禮,結(jié)果婚禮上胸竞,老公的妹妹穿的比我還像新娘欺嗤。我一直安慰自己,他們只是感情好卫枝,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布煎饼。 她就那樣靜靜地躺著,像睡著了一般剃盾。 火紅的嫁衣襯著肌膚如雪腺占。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天痒谴,我揣著相機(jī)與錄音衰伯,去河邊找鬼。 笑死积蔚,一個胖子當(dāng)著我的面吹牛意鲸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播尽爆,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼怎顾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了漱贱?” 一聲冷哼從身側(cè)響起槐雾,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎幅狮,沒想到半個月后募强,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體株灸,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年擎值,在試婚紗的時候發(fā)現(xiàn)自己被綠了慌烧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸠儿,死狀恐怖屹蚊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情进每,我是刑警寧澤汹粤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站田晚,受9級特大地震影響玄括,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肉瓦,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望胃惜。 院中可真熱鬧泞莉,春花似錦、人聲如沸船殉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽利虫。三九已至挨厚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間糠惫,已是汗流浹背疫剃。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留硼讽,地道東北人巢价。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像固阁,于是被迫代替她去往敵國和親壤躲。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容