python thrift demo
簡介
Thrift最初由Facebook研發,主要用于各個服務之間的RPC通信,支持跨語言,常用的語言比如C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml都支持。Thrift是一個典型的CS(客戶端/服務端)結構,客戶端和服務端可以使用不同的語言開發。既然客戶端和服務端能使用不同的語言開發,那么一定就要有一種中間語言來關聯客戶端和服務端的語言,這種語言就是IDL(Interface Description Language)
?
thrift使用流程
明確要交互的數據格式和具體的方法,定義出thrift接口描述文件(英文叫做IntefaceDescription File)
調用thrift工具,依據thrift接口文件,生成RPC代碼;
你的服務器端程序引用thrift生成的RPC代碼,并實現其中的Search動作的邏輯,然后啟動監聽,等待客戶端發來請求。
客戶端同樣引入并調用RPC代碼來與服務器端通信
?
thrift IDL
1. 基本類型
thrift不支持無符號類型,因為很多編程語言不存在無符號類型,比如java
bool: 布爾類型(True or False)
byte: 有符號字節
i16: 16位有符號整數
i32: 32位有符號整數
i64: 64位有符號整數
double: 64位浮點數
string: 字符串
2. 容器類型
集合中的元素可以是除了service之外的任何類型,包括exception。
list <T> : 一系列由T類型的數據組成的有序列表,元素可以重復。會被轉換成C++中的vector,Java中的ArrayList,腳本語言中的數組等。
set<T>: 一系列由T類型的數據組成的無序集合,元素不可重復。會轉換成C++中的set,Java中的HashSet、Python中的Set等
map<K,V>: 一個字典結構,key為K類型,value為V類型,相當于Java中的HMap
?
3. 結構體
就像C語言一樣,thrift也支持struct類型,目的就是將一些數據聚合在一起,方便傳輸管理。struct的定 義形式如下:
struct People {1: required string name;2: required i32 age = 20;3: optional string sex; }可以看到,結構體中每一個域都有一個正整數標識符,這個標識符并不要求連續,但一旦定義,不建議再進行修改
另外,每個域前都會有required或optional的限定,前者表示是必填域,后者則表示是可選域。域是可以有默認值的,比如上例中的“age”。
如果一個域設置為optional且在構造結構體時沒有給這個域賦值,那么在使用這個結構體時,就會忽略掉這個optional的域
?
異常(exception)
thrift支持自定義exception,規則和struct一樣,如下:
exception RequestException {1: i32 code;2: string reason; }除了使用exception來替代struct以外,“異常”這個類型,在語法上和剛才介紹過的結構體的用法是完全一致的。但是從語義上講,exception和struct卻大相徑庭。exception是在遠程調用發生異常時用來拋出異常用的
?
服務(Service)
服務的定義,與面向對象技術中定義一個接口很類似,而這些接口其實就是純虛函數。thrift編譯工具會根據服務的定義來產生相應的方法和函數。
每個服務,都包括了若干個函數,每個函數包括了若干參數和一個返回值(返回值可以是void.
(小技巧:返回值為void的函數,你可以在函數名前加上oneway標識符,將此函數以異步模式執行,這樣在調用此函數后,函數會立即返回。)
對于返回void的函數,thrift仍然會確保函數返回,這樣就表示這個函數已被正確執行,且服務器端已有返回信息了。但是如果給void的函數前加上oneway,那么此函數的返回只能表示數據已經進入傳輸層,并不能表示服務器端已經收到并返回了數據
?
service vulgar_detect{bool is_vulgar(1:string title),i32 calc(1: i32 num) }?
thrift編譯工具
在我們編寫好thrift接口描述文件之后,thrift編譯工具就要派上用場了,它的作用就是根據thrift接口描述文件來生成相應開發語言的RPC代碼.?
在終端下輸入:
Transport
Transport網絡讀寫(socket,http等)抽象,用于和其他thrift組件解耦。
Transport的接口包括:open, close, read, write, flush, isOpen, readAll。
Server端需要ServerTransport(對監聽socket的一種抽象),用于接收客戶端連接,接口包括:listen, accept, close。
python中Transport的實現包括:TSocket, THttpServer, TSSLSocket, TTwisted, TZlibTransport,都是對某種協議或框架的實現。還有兩個裝飾器,用于為已有的Transport添加功能,TBufferedTransport(增加緩沖)和TFramedTransport(添加幀)。
在創建server時,傳入的時Tranport的工廠,這些Factory包括:TTransportFactoryBase(沒有任何修飾,直接返回),TBufferedTransportFactory(返回帶緩沖的Transport)和TFramedTransportFactory(返回幀定位的Transport)。
?
?
Protocol
Protocol用于對數據格式抽象,在rpc調用時序列化請求和響應。
TProtocol的實現包括:TJSONProtocol,TSimpleJSONProtocol,TBinaryProtocol,TBinaryPotocolAccelerated,TCompactProtocol。
?
Processor
Processor對stream讀寫抽象,最終會調用用戶編寫的handler以響應對應的service。具體的Processor有compiler生成,用戶需要實現service的實現類。
?
Server
Server創建Transport,輸入、輸出的Protocol,以及響應service的handler,監聽到client的請求然后委托給processor處理。
TServer是基類,構造函數的參數包括:
1) processor, serverTransport
2) processor, serverTransport, transportFactory, protocolFactory
3) processor, serverTransport, inputTransportFactory, outputTransportFactory, inputProtocolFactory, outputProtocolFactory
TServer內部實際上需要3)所列的參數,1)和2)會導致對應的參數使用默認值。
TServer的子類包括:TSimpleServer, TThreadedServer, TThreadPoolServer, TForkingServer, THttpServer, TNonblockingServer, TProcessPoolServer
TServer的serve方法用于開始服務,接收client的請求。
?
Code generated
constants.py: 包含聲明的所有常量
ttypes.py: 聲明的struct,實現了具體的序列化和反序列化
SERVICE_NAME.py: 對應service的描述文件,包含了:
Iface: service接口定義
Client: client的rpc調用樁
?
用法
Thrift的用法實際上很簡單,定義好IDL,然后實現service對應的handler(方法名、參數列表與接口定義一致接口),最后就是選擇各個組件。需要選擇的包括:Transport(一般都是socket,只是十分需要選擇buffed和framed裝飾器factory),Protocol,Server。
?
IDL文件
/* thrift接口定義文件 */ service HelloService {string say(1:string msg) }在編輯好定義文件后, 運行如下命令,生成thrift文件。可把hello目錄移到當前目錄下,便于后面調用。
thrift -r -gen py hello.thrift?
server
# coding: utf-8 """ thrift_client.py """ import socket import sys from hello import HelloService from hello.ttypes import *from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from thrift.server import TServerclass HelloServiceHandler:def say(self, msg):ret = "Received: " + msgprint retreturn rethandler = HelloServiceHandler() processor = HelloService.Processor(handler) transport = TSocket.TServerSocket("localhost", 9090) tfactory = TTransport.TBufferedTransportFactory() pfactory = TBinaryProtocol.TBinaryProtocolFactory()server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)print "Starting thrift server in python..." server.serve() print "done!"?
?
client
# coding: utf-8 """ thrift_client.py """import sys from hello import HelloServicefrom thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocoltry:transport = TSocket.TSocket('localhost', 9090)transport = TTransport.TBufferedTransport(transport)protocol = TBinaryProtocol.TBinaryProtocol(transport)client = HelloService.Client(protocol)transport.open()print "client - say"msg = client.say("Hello!")print "server - " + msgtransport.close()except Thrift.TException, ex:print "%s" % (ex.message)?
?
小結
本文只是一個簡單的示例,在實際項目中,一般會基于zookeeper來注冊和管理服務的thrift狀態,并對server和client進一步封裝,便于在項目各個模塊中調用。
轉載于:https://www.cnblogs.com/DSKer/p/10710409.html
總結
以上是生活随笔為你收集整理的python thrift demo的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jquery iCheck 插件
- 下一篇: 对象深copy