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