(轉) Twisted : 第十二部分 改進詩歌下載服務器

新的服務器實現python

這裏咱們要新寫一個Twisted版的服務器。而後,再來討論一些Deferred的新功能。git


在第9、十部分,咱們提出了詩歌轉換引擎這個概念。因爲其實現太過簡單,所以咱們用隨機選擇來模擬了可能會出現轉換失敗的情景。但若是轉換引擎位於服務器端,那麼當服務器宕機就會出現真實的轉換失敗的情景了。github

所以,在這部分咱們要實現一個詩歌樣式轉換服務器,而後在一個部分,咱們會重寫咱們的詩歌下載客戶端來使用這一服務而且學習Deferred的新功能。編程


設計協議服務器

到目前爲止,服務器端與客戶端之間的交互都是單向的。但樣式轉換服務須要二者進行雙向交互-客戶端將原始式樣的詩歌發送給乳服務器,而後服務器將轉換格式並將其發送給對應的客戶端。所以,咱們須要使用、或本身實現一個協議來實現這種交互。網絡

咱們設計服務器端能夠提供若干種轉換服務,而讓客戶端來進行選擇。所以客戶端須要向服務器端發送兩部分信息:轉換方式名與詩歌原始內容。服務器只是將轉換格式以後的詩歌發送給客戶端。這裏使用到了簡單的運程調用函數


Twisted支持須要種協議來解決這個問題:XML-RPC,Perspective Broker,AMP性能

但介紹使用其中任何一種都須要大量的時間,所以咱們使用本身實現的協議。咱們約定客戶端發送內容格式以下:學習

轉換名稱.詩歌內容編碼

咱們將其以netstring格式編碼,固然服務器回發的信息也是以netstring格式編碼。因爲netstring使用了length-encoding,所以客戶端可以識別出服務器沒有將完整詩歌回發的狀況。若是你嘗試一下前面的協議,其沒法檢測到中途中斷傳輸的狀況。


代碼

新的服務器實現代碼在twisted-server-1/transformedpoetry.py中。首先,咱們定義了一個TransformService類:

class TransformService(object):
    def cummingsify(self, poem):
        return poem.lower()


這裏咱們僅僅實現了一種轉換方法,咱們能夠不回新格式轉換方法。有一個重要的地方須要注意:格式轉換服務與具體協議的實現是徹底分分離的。將協議邏輯與服務邏輯分開是Twisted編程中常見的模式。這樣作能夠經過多種協議實現同一種服務,以增長了代碼的重用性。

下面看看factory的實現代碼:

class TransformFactory(ServerFactory):
    protocol = TransformProtocol
    def __init__(self, service):
        self.service = service
    def transform(self, xform_name, poem):
        thunk = getattr(self, 'xform_%s' % (xform_name,), None)
        if thunk is None: # no such transform
            return None
        try:
            return thunk(poem)
        except:
            return None # transform failed
    def xform_cummingsify(self, poem):
        return self.service.cummingsify(poem)

factory提供了一個transform的函數,protocol就是用它來表明客戶端鏈接請求進行詩歌格式轉換。

若是發現沒有客戶端請求的轉換方法或轉換失敗,那麼返回None。和TransformService同樣,factory與具體的協議邏輯實現也是相互獨立的。

有一個地方須要引發注意:咱們經過xfomr_前綴式方法來獲取服務方法。這種方法在Twisted中很常見,儘管前綴常常發生變化,而且他們常常是依賴於獨立於factory的一個對象(如此處的 TransformService)這是一種防止客戶端使用蓄意惡性代碼來讓服務器端執行的方法。這種方法也提供了實現由服務提供具體協議代理的機制。

下面是協議實現代碼:

class TransformProtocol(NetstringReceiver):
    def stringReceived(self, request):
        if '.' not in request: # bad request
            self.transport.loseConnection()
            return
        xform_name, poem = request.split('.', 1)
        self.xformRequestReceived(xform_name, poem)
    def xformRequestReceived(self, xform_name, poem):
        new_poem = self.factory.transform(xform_name, poem)
        if new_poem is not None:
            self.sendString(new_poem)
        self.transport.loseConnection()

在這個協議的實現中,咱們經過繼承NetstringReceiver來利用了Twistednetstrings的實現。基類很好的處理了編碼與解碼功能,咱們須要作的就是實現stringReceived方法。換句話說,stringReceived接收的參數是客戶端編碼以後的詩歌,而無需咱們再去添加額外的編碼信息。並且基類一樣管理着緩衝區,即當一首詩歌完整接收完再進行解碼。

若是一切進展正常的話,咱們會使用NetstringReceiver的 sendString方法來將格式轉換成功後的詩歌發送給客戶端。

注意咱們是如何經過定義xformRequestReceived方法將收到的信息一步步推向更高的抽象層而實現了Twisted的模式。


一個簡單的客戶端

咱們會在下一個部分來實現相應的客戶端,這裏使用一個簡單的腳原本實現客戶端,代碼位於twisted-server-1/transform-test中。若是你運行服務器端於11000端口:

python twisted-server-1/transformedpoetry.py --port 11000

相應的運行腳本爲:

./twisted-server-1/transform-test 11000

那麼你會看到以下輸出(通過netstring編碼):

15:here is my poem,

討論

在這個部分介紹了以下幾個方面內容:

1.雙向通訊

2.基於Twisted已有的協議實現新協議

3.將協議實現與服務功能實現獨立分開

雙向通訊的基本機制是很簡單的。咱們使用前面服務器端與客戶端使用的相同的技術來寫與讀數據,惟一不一樣的是咱們此次二者都使用了(讀與寫)。固然,一個複雜的協議須要複雜的代碼來處理接收到的數據流與格式化輸出的信息。這也是爲何使用已經存在的協議的緣由。

若是你開始以爲寫簡單的協議已經很上手了,那麼最好就開始看看Twisted對不一樣協議的實現。儘管寫一些簡單的協議有助理解Twisted的編程風格,但在一個真實的程序中,最好是複用那些已經實現並證實性能良好的協議。

最後一點是將協議解析邏輯與服務實現邏輯分開,這是Twisted編程中很是重要的一個模式。咱們這個服務器程序只是一個演示,你能夠想象一下真實的網絡服務是至關複雜的。經過將服務與協議邏輯分開,你能夠經過複用已有的服務代碼來運行於其它的協議實現上。

27展現了一個格式轉換服務器經過兩種協議提供格式轉換服務(固然,咱們的服務器只提供了一種協議):

第十二部分 <wbr>改進詩歌下載服務器

27 提供兩種協議支持的格式轉換服務器

雖然在圖27中使用了兩種協議,但他們也許是隻有幾個協議屬性不一樣。factory共享相同的服務。這樣實現了代碼的複用。

相關文章
相關標籤/搜索