預覽
twisted是一個被設計的非常靈活架構以至於能夠讓你寫出非常強大的伺服器。這種靈活的代價是需要好通過好幾個層次來實現你的伺服器, 本文檔描述的是Protocol層,你將在這個層次中執行協議的分析和處理,如果你正在執行一個應用程式,那麼你應該在讀過top level的為twisted寫外掛程式一節中的怎樣開始寫twisted應用程式之後閱讀本章。這個文檔只是和TCP,SSL和Unix通訊端伺服器有關,同時也將有另一份文檔專門講解UDP。
你的協議處理類通常是twisted.internet.protocol.Protocol的子類。許多協議處理繼承於該類或者比該類更加方便的該類的子類。一個protocol類的執行個體可能反覆串連,也可能在串連關閉之後銷毀。這就意味著這些持續不斷的配置資訊不是儲存在Protocol中。
這些持久性的配置被儲存在工廠(Factory)類中,這些工廠類通常繼承至twisted.internet.protocol.Factory,預設 的工廠類僅僅是執行個體化每個Protocol,然後設定他們的factory屬性為這個預設的工廠執行個體本身。這就讓每個Protocol都被儲存,然後可能 修改,於是這樣就形成了Protocol的持久性。
通常為多個連接埠或網路地址提供相同的服務是非常有用的。這就是為什麼Factory不監聽串連,並且實際上它不知道關於網路的任何事情。看 twisted.internet.interfaces.IReactorTCP.listenTCP,另一個IReactor*.listen*獲得 更多的資訊。
本文檔將要講解各個步驟。
Protocol
如上所述,這裡將通過更多代碼的輔助類和函數來瞭解它。一個twisted protocl通過非同步方式處理資料。這就意味著protocol從不等待任何事件。相反的是在事件通過網路到達的時候作出響應。
from twisted.internet.protocol import Protocolclass Echo(Protocol): def dataReceived(self,data): self.transport.writed(data)
這是個非常簡單的協議處理,僅僅是在獲得資料的事件中簡單的將接收到的資料發送回去,並沒有對所有的事件進行響應。這裡有一個Protocol響應其他事件的例子如下:
from twisted.internet.protocol import Protocolclass QOTD(Protocol): def connectionMade(self): self.transport.write("An apple a day keeps the doctor away/r/n") self.transport.loseConnection()
本Protocl在一個已知的引用剛開始串連上來的時候作出響應,發送了一條訊息,然後終止了串連connectionMade事件通常是在由於連線物件建立初始串連時觸發,就像上面的QOTD類實際上是RFC865號文檔的一個協議基類connectionLost事件將在中斷連線的時候觸發。執行個體:
PythonCode:
from twisted.internet.protocol import Protocol class Echo(Protocol): def connectionMade(self): self.factory.numProtocols = self.factory.numProtocols+1 if self.factory.numProtocols > 100: self.transport.write("Too many connections, try later") self.transport.loseConnection() def connectionLost(self, reason): self.factory.numProtocols = self.factory.numProtocols-1 def dataReceived(self, data): self.transport.write(data) |
本執行個體中,connectionMade和connectionLost相互協作工作以保持factory內部的活動串連數量最多為100。每當有使用者協議串連近來的時候,就先檢測factory內部的活動串連數,如果數量超過100,就發送串連數太多等下試的訊息,然後中斷連線而connectionLost則在斷開一個協議的時候觸發,減去factory內部的協議數量。
Using the Protocol
在本節,我將要講解怎樣簡單的去測試你的protocol。(想知道如何寫出一個好的twisted的伺服器,請看 Writing Plug-Ins
for Twisted),這裡有一個代碼將運行我們上面談論的QOTD伺服器:
PythonCode:
from twisted.internet.protocol import Protocol, Factory from twisted.internet import reactor class QOTD(Protocol): def connectionMade(self): self.transport.write("An apple a day keeps the doctor away/r/n") self.transport.loseConnection() # Next lines are magic: factory = Factory() factory.protocol = QOTD # 8007 is the port you want to run under. Choose something >1024 reactor.listenTCP(8007, factory) reactor.run() |
不必擔心最後面的6條代碼,稍後你將會在本文檔中瞭解到他們。
Helper Protocols
大部分protocols依賴於同類別的更低層次的超級類。最受歡迎的互連網協議是基於行,行通常是由CR_LF(斷行符號換行組成)
然而,也有相當一部分協議是混合的,他們具有線性基本節點,也有未經處理資料節點,比如HTTP/1.1。
在這樣的情況下,我們可以使用LineReceiver,本協議類有兩個不同的事件處理方法,lineReceived和rawDataReceived
預設情況下,只有lineReceived會被調用,每次讀取一行,然而如果setRawMode被調用,protocol將調用rawDataReceived
來處理直到setLineMode被調用。下面有一個簡單的例子說明如何使用lineReceiver:
PythonCode:
from twisted.protocols.basic import LineReceiverclass Answer(LineReceiver): answers = {'How are you?': 'Fine', None : "I don't know what you mean"} def lineReceived(self, line): if self.answers.has_key(line): self.sendLine(self.answers[line]) else: self.sendLine(self.answers[None])
注意:界定符不是命令列的一部分
其他也有一些不流行的協議依然存在,比如netstring based 和 a prefixed-message-length
State Machines
許多twisted protocol handlers需要編寫一個狀態機器來記錄他們當前的狀態,這裡有幾點編寫狀態機器的建議:
1、不要編寫大狀態機器,寧願去實現一個抽象的狀態機器類
2、使用python的動態性質去建立沒有限制的狀態機器,比如SMTP用戶端
3、不要混合特定應用程式代碼和協議處理代碼,當協議處理器已經提出一個特別的具體要求,保持它作為一個方法調用。
Factories(工廠類)
如前面所說,通常twisted.internet.protocol.Factory不必子類化就可以開始工作。然而有時候protocol需要具體的
特殊的工廠配置資訊或其他需求,在這樣的情況下,就需要進行子類化了。
對於Factory來說,他只是簡單的執行個體化特殊的 protocol協議類,執行個體化Factory,並且設定protocol屬性:
PythonCode:
from twisted.internet.protocol import Factoryfrom twisted.protocols.wire import EchomyFactory = Factory()myFactory.protocol = Echo
如果需要簡單的去構造一個有具體特殊資訊的工廠類,那麼一個factory函數是非常有用的:
PythonCode:
class QOTD(Protocol): def connectionMade(self): self.transport.write(self.factory.quote+'/r/n') self.transport.loseConnection()def makeQOTDFactory(quote=None): factory = Factory() factory.protocol = QOTD factory.quote = quote or 'An apple a day keeps the doctor away' return factory
一個Factory有兩個方法以執行特定於應用程式的建立和拆除(由於一個Factory通常存在,所以常規下一般不在__init__或者
__del__中給他們分配與回收,有可能太早或太晚)。
下面是一個Factory的例子,本例將允許Protocol寫一個記錄檔:
PythonCode:
from twisted.internet.protocol import Factoryfrom twisted.protocols.basic import LineReceiverclass LoggingProtocol(LineReceiver): def lineReceived(self, line): self.factory.fp.write(line+'/n')class LogfileFactory(Factory): protocol = LoggingProtocol def __init__(self, fileName): self.file = fileName def startFactory(self): self.fp = open(self.file, 'a') def stopFactory(self): self.fp.close()
Putting it All Together(綜合)
現在你已經瞭解了Factory並且想要執行QOTD作為一個可配置的quote伺服器是嗎?沒有問題這裡就有一個代碼:
PythonCode:
from twisted.internet.protocol import Factory, Protocolfrom twisted.internet import reactorclass QOTD(Protocol): def connectionMade(self): self.transport.write(self.factory.quote+'/r/n') self.transport.loseConnection()class QOTDFactory(Factory): protocol = QOTD def __init__(self, quote=None): self.quote = quote or 'An apple a day keeps the doctor away'reactor.listenTCP(8007, QOTDFactory("configurable quote"))reactor.run()
就是最後兩句代碼,還需要去理解。
listenTCP是一個將Factory串連到網路的方法,他使用了reactor的介面,讓許多不同的迴圈處理網路代碼,而不需要修改的
終端使用者代碼,就像這樣。如前面所說,如果你想要寫一個好的twisted伺服器,而不是僅僅的20行,那麼你需要使用 the Application object.