1.thrift的數據類型。(這里主要為翻譯官方文檔)
a. 基本數據類型
1) boolean型,值為true或false
2) byte型,值為單字節字母
3) i16型,值長度為16位的integer帶符號數字.
4) i32型,值長度為32位的integer帶符號數字.
5) i64型,值長度為64位的integer帶符號數字.
6) double型,值長度為64的浮點數.
7) string型,字符串或者binary數據。
b. 結構體
有點類似c的結構體。不怎么懂c的同學可以理解為不帶方法的類,只有屬性而已。
型如:
struct Work { 1 : i32 num1 = 0 , 2 : i32 num2, 3 : Operation op, 4 : optional string comment, }
?
c. 容器
1) list類型。
指一組有序元素的集合,類似于java的ArrayList類。
typedef i32 MyInteger MyInteger a; struct hello{ list <MyInteger> d; }
指hello結構體中含有一個list類型的數據,且里面的元素都必須是a數據類型的MyInteger數據類型的數據,主要這里的typedef起一個別名的作用。
2) set類型
一個不可重復的排序元素的集合,類似java的hashset,python的set.使用同list
3)?map<type1,type2>類型。
使用如:
map< string , string > MAPCONSTANT = { ' hello ' : ' world ' , ' goodnight ' : ' moon ' }
4) 枚舉類型
?
2. 服務
有了數據結構,那么就該對數據進行操作。thrift這里所說的服務,不可能針對我們自己的業務邏輯,而是指的是服務端從端口讀取數據,客戶端傳入數據的一套方法。
service <服務名>{ <返回類型> <方法名>(參數) throws <異常> }
3. 實踐:
根據前面所說數據類型和結構體,編寫如下thrift文件,名為 test.thrift
i32 a; i32 b; string c; list < string > d; map < string , string > e = { " hello " : " world " , " dd " : " ee " }; struct f{ 1 :a, 2 :b, 3 :c= 2 , 4 :d= " ceshi " , 5 :e, } service Hello{ f get_f( 1 :f gg) throws (Exception, e) }
以上代碼使用thrift的標準命令(thrift.exe -gen py test.thrift)是不成功,因為語法還是不正確!
修改
1.常量量如a,b,c,d, e要使用const修飾。
2. 如果都使用了const修飾,但有;號,還是不成功,盡管有的人說thrift對;不敏感,那還是估計看版本的,這里我使用的是最新的0.8版本。也就是說,如果你是一個java或者php程序員,請注意沒有";"
3. 靜態變量請賦值,如const i32 a = "helloworld"
4. 結構體內部的屬性請指定參數類型,因為結構體內部屬性和外部的靜態屬性沒有任何關系。
5. 異常之間沒有“,”分割,以空格代替
6. Exception類型請定義。
7. throws參數也要指定是第幾個參數
好了,修改后的thrift腳本變為
const i32 a = 1 const i32 b = 2 const string c = " helloworld " const list< string > d = " test " const map< string , string > e = { " hello " : " world " , " dd " : " ee " } struct f{ 1 :i32 a, 2 :i32 b, 3 : string c, 4 :list< string > d=[ " ceshi " ], 5 :map< string , string > e = { " hello " : " world " }, } exception Exception{ 1 :i32 what; 2 : string where ; } service Hello{ f get_f( 1 :f gg) throws ( 1 :Exception e) }
稍微有那么一點像生產環境了,生成代碼結構:
我們可以讓這個隨便編寫的腳本為我們完成一點點功能,比如get_f讓他對結構體f的對象gg的各種值計算,當然生成環境也可以集成數據庫了。
?
那么現在需要幾個數據通信接口了。
1.?讀取數據:readMessageBegin()
(fname, mtype, rseqid) = self._iprot.readMessageBegin()
從端口讀取請求流,獲取3個值。
readMessageEnd() 讀取數據結束。
2.?readStructBegin() 開始讀取結構體
readStructEnd() 讀取結構體結束
3.?readFieldBegin() 讀取屬性開始
readFieldEnd()
4.?readMapBegin()讀取map開始
readMapEnd()讀取map結束。
這里的數據接口還有很多,不一一列舉,因為我們在實際使用thrift的時候,只要不類似于修改thrift源碼的操作,都不需要關心這些具體的數據操作。
?
接下來我們做客戶端和服務端的操作,同時在服務端進行具體業務的處理。
?
1. 編寫借口類.
import sys sys.path.append( " ../gen-py " ) from cc import Hello from cc import ttypes class My_Handler(Hello.Iface): def get_f(self, gg): #對對象gg進行梳理 gg.a = gg.a + gg.b gg.b = gg.a - gg.b return gg
官方事例的CalculatorHandler是不繼承Iface的,而我這里采用繼承Hello.Iface,并沒有別的深意,是表示一定要有我們定義thrift文件的get_f方法。假如我們的邏輯更加復雜,handler處理里有數據庫操作等等,繼承不繼承Iface都是可以的。
官方的handler(部分):
class CalculatorHandler: def __init__(self): self.log = {} def ping(self): print ' ping() ' def add(self, n1, n2): print ' add(%d,%d) ' % (n1, n2) return n1+n2
接下來要對這個handler要對這個hander進行處理:
import sys sys.path.append( " ../gen-py " ) from cc import Hello from cc import ttypes class My_Handler(Hello.Iface): def get_f(self, gg): #對對象gg進行梳理 gg.a = gg.a + gg.b gg.b = gg.a - gg.b return gg handler = My_Handler() process = Hello.Processor(handler) from thrift.transport.TSocket import TServerSocket server = TServerSocket(host= " localhost " , port = 9090 ) from thrift.transport.TTransport import TBufferedTransportFactory tfactory = TBufferedTransportFactory() from thrift.protocol.TBinaryProtocol import TBinaryProtocolFactory bfactory = TBinaryProtocolFactory() from thrift.server.TServer import TSimpleServer servers = TSimpleServer(process, server, tfactory, bfactory) print " starting the server... " servers.serve() print " done... "
直接上代碼了。注意,這里的TServerSocket一定要指定,因為官方的類初始化時host賦初值居然寫的none,等于沒有寫麼。
class TServerSocket(TSocketBase, TServerTransportBase): """ Socket implementation of TServerTransport base. """ def __init__(self, host =None, port= 9090 , unix_socket=None):
一個沒有host的服務,可以想象會是什么樣子,使用netstat -na查看端口:
TCP [::]:9090 [::]:0 LISTENING
就是沒有host導致的情況。
一個host定義為localhost的服務,使用netstat -na查看端口:
TCP 127.0.0.1:9090 0.0.0.0:0 LISTENING
?
接下來編寫客戶端,客戶端的編寫主要是是實例化Hello.Client對象
__author__ = ' CLTANG ' # ! -*- encoding:utf- 8 -*- ''' 客戶端 ''' import sys sys.path.append( " ../gen-py " ) from cc import Hello from cc import ttypes from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol.TBinaryProtocol import TBinaryProtocol transport = TSocket.TSocket( ' localhost ' , 9090 ) # Buffering is critical. Raw sockets are very slow transport = TTransport.TBufferedTransport(transport) # Wrap in a protocol protocol = TBinaryProtocol(transport) client = Hello.Client(protocol) transport.open() ff = ttypes.f(a= 1 ,b= 2 ) results = client.get_f(ff) print results transport.close()
執行客戶端程序,最終將輸出:
f(a=3, c='helloworld', b=1, e={'cc': 'dd', 'ee': 'ff'}, d=['hello', 'world'])
達到了我們最早定義在test.thrift中的service的內容,即傳入f類型的實例化對象,調用get_f方法,返回一個經過處理的f類型的實例化對象。
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
