本文按照以下結構介紹thrift
1. thrift是什么?
2. thrift能做什么
3. thrift和其他類似東西的對比
4. 我們使用thrift要做什么
好,先按照上面結構介紹。
1. thrift是什么?
官網上介紹得我不在累述,自己google其他關於thrift的文章,會有很多,比如"是apache的一個項目,和facebook有關系"等。我總結一句話:
thrift是跨語言,server和client通信的一個框架,支持多種協議,二進制,文本http,json等方式,提供高效的數據傳輸方式。
2. thrift能做什么?
thrift只負責對數據進行處理,然后在網絡內進行傳輸的工作。不要認為thrift能在*.thrift文件中定義調度之類的工作。
3. thrift和其他東西對比
網上同thrift人們經常對比的dubbo,阿里巴巴的東西,還沒研究。只說自己想對比的。
twisted。 python的一個網絡編程框架。
twisted可thrift其實沒有可比性,twisted客戶端和服務器端都要求使用python,而thrift卻不必,支持的語言很多,大眾語言基本都有。而作為一個python程序員,自認為twisted很曲折的學習曲線。thrift的學習卻很平滑,平滑。也就是說,如果你熟悉你所使用的語言,寫一個thrift服務相當簡單。當然了,twisted的作用可不是這一個。
cheerypy。python的一個網絡編程框架。
服務器端同客戶端的數據傳輸最讓人容易想到的是http協議傳輸。所以,任何一個做BS的架構都可以做類似工作,只是別有界面而已。thrift說自己使用了二進制流進行數據傳輸,是高效的,而普通的http協議是文本傳輸,或者xml,或者json,所以在數據傳輸上thrift是高效的。關於這一點,需要具體看你項目中是否有類似需求,如果在2台機器之間,你們傳輸的只是一些配置文件之類的工作,完全沒有必要。如果你在2台機器之間傳輸的是大日志,不錯,可以考慮。
4. 使用thrift我們要做什么?
按以下結構介紹。
a. 學習安裝
b. 學習*.thrift文件的編寫。
c. 使用thrift命令生成協議文件等。
d. 編寫自己的服務器端。
e. 編寫自己的客戶端。
f. 測試。
a. 安裝thrift.(windows下)
安裝exe格式吧,windows你不用關心什么mingw, 到http://www.apache.org/dyn/closer.cgi?path=/thrift/0.8.0/thrift-0.8.0.exe下載一個文件。
。
下載成功后在windows下使用這個文件有2種方法。1.將這個文件copy至項目目錄,同*.thrift文件同目錄。2將這個文件copy至c:/windows目錄,一般windows目錄都是鍵入到環境變量的。像我的就是:
, 在C:\Windows文件夾里。並且將文件的-0.8.0去掉了,方便使用命令。如果你願意,寫成什么都行。我這里玩了下,寫成1.exe了。
照樣正確。不過最好還是改過來,免的自己忘了自己這么玩過。這里就表示可以使用在任意位置使用thrift命令了。
b. thrift文件的編寫。
我們知道,計算機語言必須有一個編譯器,不管是C,python,php,python和php核心東西都是c寫的,有人在說C是什么寫的。或者問得不對,C的編譯器是什么寫的,因為一門語言的語法只是人們定義的一種格式,而最重要的是解析這些“代碼”的編譯器,有人說C的編譯器也是C寫的,有人不明白,追問為什么,那么最終其實可以解釋成高階的編譯器逐漸在計算機語言發展的過程中沿用了歷史給我們的遺產。那thrift這里總是在告訴我們一個名詞,叫The Thrift interface definition language(IDL), thrift接口定義語言。由名稱我們知道,這門語言是定義接口的,熟悉java的朋友一定非常清楚這個名詞,不做具體業務的一門語言。那它有沒有其他語言的特征呢,首先已經由他不做具體業務處理知道他少東西。但是他能做另外的事。
除了定義服務接口,他還能定義數據類型。但他不向內存申請空間來他任何和這個數據類型有關的操作,而只是做將這你所編寫的*.thrift文件進行轉型,轉為你所熟悉的語言的代碼!
所以,thrift是什么,是一個代碼轉換框架,將*.thrift轉換為你說熟悉的語言,並且完成了一些代碼,減少了你的代碼編寫量,但有學習成本。
至於語法請參看http://hi.baidu.com/o%CB%AF%D1%DB%EB%FC%EB%CA%B5%C4%D6%EDo/blog/item/6d1d4dac9f66b1a9ca130c37.html,網絡很多這方面的東西。
現在先做個demo:
1. 先建立一個文件夾。
里面什么都沒有。
2. 建議一個test.thrift文件。
新建立一個thrifttest.thrift文件了,但里面什么都沒有。需要你自己編寫thrifttest.thrift文件
struct File { 1:string path, 2:string data, } service HelloWorld { void ping() string copy(1:string path) }
。我們還需要做文件copy的操作。從服務器端copy文件到客戶端。因為這樣更符合使用thrift使用的條件。
有意思的編輯thrift文件,寫個string copy(1:string path),把方法的返回值,方法名,方法參數都已經確認好了。即結構為 【返回值類型 方法名(參數類型 參數名稱)】注意,這里如果是多個結構體,定義參數名稱的時候最好不一樣。
3. 使用命令生成代碼
沒有錯誤。表示代碼生成了。這里thrifttest目錄是服務器端
沒有錯誤。表示代碼生成了。這里thrifttest-client是客戶端。
4. 編寫服務器端代碼。
#!/usr/bin/env python import sys sys.path.append('../gen-py') from thrifttest import HelloWorld from thrifttest.ttypes import * from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from thrift.server import TServer import socket class HelloWorldHandler: def __init__(self): self.log = {} def ping(self): print "ping()" def copy(self, path): print 'path',path with open(path, "rb") as f: data = f.read() return data handler = HelloWorldHandler() processor = HelloWorld.Processor(handler) transport = TSocket.TServerSocket("localhost",30303) tfactory = TTransport.TBufferedTransportFactory() pfactory = TBinaryProtocol.TBinaryProtocolFactory() server = TServer.TSimpleServer(processor, transport, tfactory, pfactory) print "Starting python server..." server.serve() print "done!"
注意這里的handler有2個處理方法,一個是ping(),一個是copy方法。ping方法是檢查當前是否連接。copy做我們具體的業務,這里我們做的是讀文件,你也可以用這個方法來寫一個數據庫查詢,等等,反正這里已經獨立出來了,只不過返回的數據我們定義的是string類型。別的類型你可以自己測試。
那么當前服務器端程序目錄結構就是:
5. 編寫客戶端代碼.
#!/usr/bin/env python import sys sys.path.append('../gen-py') from thrifttest import HelloWorld from thrifttest.ttypes import * from thrifttest.constants import * from thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol try: # Make socket transport = TSocket.TSocket('localhost', 30303) # Buffering is critical. Raw sockets are very slow transport = TTransport.TBufferedTransport(transport) # Wrap in a protocol protocol = TBinaryProtocol.TBinaryProtocol(transport) # Create a client to use the protocol encoder client = HelloWorld.Client(protocol) # Connect! transport.open() client.ping() print "ping()" data = client.copy("D:\\helloworld.html") print data transport.close() except Thrift.TException, tx: print "%s" % (tx.message)
這里所有個client可以調用我們服務器端方法。參數也是,簡直就是像在一台機器上執行一樣。0-0,我就是在一台機器上執行的,不過是2個進程而已,玩笑。也算進程間通信了。。。
當前代碼結構如下圖:
好。測試。
服務器端啟動:
Starting python server...
客戶端啟動:
Sping() dfslfdjslfjdsldfjlskfjlsdjflsjdol
在客戶端立馬有了一段字符串,這段字符串d:/helloworld.html的內容。
而此時在服務器端打印出:
Starting python server... ping() path D:\helloworld.html
現在把文件變成10M的
修改客戶端代碼:
data = client.copy("D:\\nEOiMAGING_3.1.2.104_DownG.com.rar") with open("E://test.rar", 'wb') as f: f.write(data) end_time = time.time() all_time = end_time - start_time print all_time
執行結束后E盤有了 test.rar文件,輸出
ping() 0.771000146866
時間是很短的。當然這是12M文件。不能說明什么問題。我們換個大的。
換成一個一個多G的文件。這時可能就要出錯。
在客戶端提示說:
ping() TSocket read 0 bytes
而服務器端提供的錯誤提示:
File "E:/workspace/thrifttest/gen-py/thrifttestservice.py", line 27, in copy data = f.read() MemoryError
但是出錯並不影響當前服務的繼續運行。
所以,thrift並不是想象中的那么高深,每個技術看他官方 文檔的時候,都說的玄乎,不管是python介紹,還是thrift,django,scrapy,說的是自己厲害的,其實咱做技術的更應該關心那些場景他不適合。別亂用技術。別圖新鮮胡亂用在某個項目中。