twisted系列教程十二–为server 增加一个service
One More Server
 在第九部分和第十部分我們介紹了關于詩歌的變形引擎的想法,最后我們實現了cummingsifier,我們還讓它拋出隨機的異常來模擬錯誤.但是假如這個變形的引擎在另外一臺服務器上,提供一種網絡的”poetry transformation service”, 那么現在又多出來一種出錯的方式:變形引擎掛掉了.
 所以在第十二部分我們將要實現一個poetry transformation server,并在下一部分,我們讓我們的client 使用一個外部的transformation service,并從中學到Deferred 的一些東西.
 Designing the Protocol
 到現在為止client 和server 端的交互都是單向的,server 端向client端發送一首詩,而client 什么也向server 發送.但是一個transformation service 是雙向的– client 端向server發送一首詩然后服務端發送給client 一首變形后的詩.所以我們需要一個新的protocol來處理這種交互.
 在我們實現這個的時候,我們讓server 支持多種的變形方式,并讓client 可以選擇使用哪一種.所以client 需要發送給server兩個數據:變形的方式和這首詩的內容.我們的server 會返回變化后的詩.所以呢,我們已經完成了一個簡單的Remote Procedure Call.
 twisted 包含了幾個實現這個問題的幾種protocol,包括XML-RPC, Perspective Broker, 和 AMP.
 但是呢,用這些已經實現了的protocol 會讓我們走的太遠了,所以最好我們還是自己實現一個.讓我們的client 發送一個如下的字符串:
 .
 也就是一個變形引擎的名字和這首詩歌的內容中間用一個點連接.我們還會把這個字符串編碼成netstring 的形式.server 端會返回已經變形過的詩,也是netstring 的方式.因為netstring 使用了帶長度的編碼,client 可以檢測到是否server端發送了一個完整版本的詩.如果你回想一下的話,我們原來的protocol 很難檢測到中途停止發送的情況.
 有關protocol 的設計先介紹這些,對于我們來說已經夠用了.
 The Code
 讓我們來看一下我們的ransformation server,在 twisted-server-1/transformedpoetry.py,首先,我們定義了一個TransformService 類:
 class TransformService(object):
 ????def cummingsify(self, poem):
 ????????return poem.lower()
 這個transform service 目前只支持一種變形–cummingsify.通過一個同名方法.我們還可以增加其他的算法.我們需要注意的是:transformation service 是完全獨立于我們之前所說的protocol 的.把protocol 的邏輯和 service 的邏輯分開在twisted 編程中是一個經常用的模式.這樣做的話可以通過不同的protocol 來提供相同的transformation service而不用修改太多的代碼.
 下面讓我們看一下protocol 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 提供了一個變形的方法,一個protocol 可以用它來得到一個poetry transformation.如果沒有這個方法相對應的transformation或這個transformation失敗了,這個方法會返回None.就像TransformService 一樣,這個protocol factory 和protocol 也是相互獨立的,但是factory 中的方法protocol 都是可以調用的.
 你需要注意的是我們是怎樣保護帶有xform_前綴地 方法.這是一種在twisted 源碼中經常用的模式.這是一種防止客戶端的代碼直接調用service 對象方法的方法,因為客戶端可能傳遞過來任何的 transform name.
 下面我們來看一下protocol 的實現:
 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()
 在protocol 的實現中我們利用了Twsited 已經實現的NetstringReceiver protocol.這個基類會負責netstring 的編碼和解碼,我們所要去做的就是實現stringReceived 方法.換句話說,stringReceived會被傳遞進從client 那邊接收過來的詩的內容.這個基類也會負責緩沖傳進來的數據直到我們有足夠的數據去解碼出來一首完整的詩.
 假如一切都正常的話我們會通過NetstringReceiver 提供的sendString方法發送變過形的詩到客戶端.這就是全部要做的工作.main 函數由于沒有什么變化,我們在這里就不講了.
 注意我們是怎樣通過定義xformRequestReceived 方法利用twisted 模式將傳進來的字節流變化成更高級的抽象,最后xformRequestReceived 被傳遞進兩個參數–一個是變形的名字另一個是詩的內容.
 A Simple Client
 在第十三部分我們會實現一個利用ransformation service 的twisted client.但現在我們僅僅用一段腳本來測試我們的server,代碼在twisted-server-1/transform-test.它用netcat程序向server 發送一首詩歌的內容并打印出返回的結果.讓我們先開啟我們的server:
 python twisted-server-1/transformedpoetry.py --port 11000
 然后運行我們的測試腳本:
 ./twisted-server-1/transform-test 11000
 你看看到下面的額輸出:
 15:here is my poem,
 Discussion
 在這一部分我們介紹了一些新的想法:
 ????雙向的通信
 ????在twisted 已經提供的protocol 實現上進行編程
 ????使用一個service 對象來分開功能邏輯和protocol 邏輯
 ?
 雙向通信的結構是非常簡單的,讀數據和寫數據中我們都使用了同樣的技術,與之前的server 和client 不同的是我們同時使用了它們兩個.當然,一個更復雜的protocol會需要更復雜的代碼來處理字節流,這也是我們為什么使用了一個已經存在的protocol 實現.
 一但你熟悉了一些基本的protocol 的實現,建議你去看看twisted 自帶的一些復雜的協議.你可以從twisted.protocols.basic 模塊讀起.寫一些簡單的protocol 是你熟悉twisted 編程的很好的方式.在一些真正twisted 程序中,更有可能去使用一個已經被實現的protocol.
 使用一個service對象來把功能邏輯和protocol邏輯分開在twisted 編程中是一個很重要的設計模式,盡管我們今天將的這個變形的service 不是特別重要,你可以想象在一個大型的應用中一個service可能會非常復雜.通過讓service 和 protocol 分離,我們可以快速的在不同的protocol上提供相同的service.
 圖片二十七描述了一個transformation server通過兩種不同的protocol 的來進行服務:
 圖片二十七
 盡管我們需要兩個protocol factory,它們可能也就protocol 不同.這個兩個protocol factory共用一個service 對象,剩下的就是protocol 需要分開實現.這樣我們就實現了數據復用.
 Looking Ahead
 有關我們的transformation server 暫時就講這么多,在第十三部分,我們會繼續改進我們的client,讓它可以直接利用我們的service.
總結
以上是生活随笔為你收集整理的twisted系列教程十二–为server 增加一个service的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: SQLAlchemy 教程 —— 基础入
 - 下一篇: Python动态导入模块、类