Twisted是用Python實現的基於事件驅動的網路引擎框架,Twisted支持許多常見的傳輸及應用層協議,包括TCP、UDP、SSL/TLS、HTTP、IMAP、SSH、IRC以及FTP。就像Python一樣,Twisted也具有“內置電池”(batteries-included)的特點。Twi ...
Twisted是用Python實現的基於事件驅動的網路引擎框架,Twisted支持許多常見的傳輸及應用層協議,包括TCP、UDP、SSL/TLS、HTTP、IMAP、SSH、IRC以及FTP。就像Python一樣,Twisted也具有“內置電池”(batteries-included)的特點。Twisted對於其支持的所有協議都帶有客戶端和伺服器實現,同時附帶有基於命令行的工具,使得配置和部署產品級的Twisted應用變得非常方便。
Transports
Transports代表網路中兩個通信結點之間的連接。Transports負責描述連接的細節,比如連接是面向流式的還是面向數據報的,流控以及可靠性。TCP、UDP和Unix套接字可作為transports的例子。它們被設計為“滿足最小功能單元,同時具有最大程度的可復用性”,而且從協議實現中分離出來,這讓許多協議可以採用相同類型的傳輸。Transports實現了ITransports介面,它包含如下的方法:
write 以非阻塞的方式按順序依次將數據寫到物理連接上
writeSequence 將一個字元串列表寫到物理連接上
loseConnection 將所有掛起的數據寫入,然後關閉連接
getPeer 取得連接中對端的地址信息
getHost 取得連接中本端的地址信息
將transports從協議中分離出來也使得對這兩個層次的測試變得更加簡單。可以通過簡單地寫入一個字元串來模擬傳輸,用這種方式來檢查。
Protocols
Protocols描述瞭如何以非同步的方式處理網路中的事件。HTTP、DNS以及IMAP是應用層協議中的例子。Protocols實現了IProtocol介面,它包含如下的方法:
makeConnection 在transport對象和伺服器之間建立一條連接
connectionMade 連接建立起來後調用
dataReceived 接收數據時調用
connectionLost 關閉連接時調用
Reactor模式
Twisted實現了設計模式中的反應堆(reactor)模式,這種模式在單線程環境中調度多個事件源產生的事件到它們各自的事件處理常式中去。
Twisted的核心就是reactor事件迴圈。Reactor可以感知網路、文件系統以及定時器事件。它等待然後處理這些事件,從特定於平臺的行為中抽象出來,並提供統一的介面,使得在網路協議棧的任何位置對事件做出響應都變得簡單。
Deferreds
Deferred對象以抽象化的方式表達了一種思想,即結果還尚不存在。它同樣能夠幫助管理產生這個結果所需要的回調鏈。當從函數中返回時,Deferred對象承諾在某個時刻函數將產生一個結果。返回的Deferred對象中包含所有註冊到事件上的回調引用,因此在函數間只需要傳遞這一個對象即可,跟蹤這個對象比單獨管理所有的回調要簡單的多。
Deferred對象包含一對回調鏈,一個是針對操作成功的回調,一個是針對操作失敗的回調。初始狀態下Deferred對象的兩條鏈都為空。在事件處理的過程中,每個階段都為其添加處理成功的回調和處理失敗的回調。當一個非同步結果到來時,Deferred對象就被“激活”,那麼處理成功的回調和處理失敗的回調就可以以合適的方式按照它們添加進來的順序依次得到調用。
非同步版URL獲取器採用Deferred對象後的代碼如下:
from twisted.internet import reactor
import getPage
def processPage(page):
print page
def logError(error):
print error
def finishProcessing(value):
print "Shutting down..."
reactor.stop()
url = "http://google.com"
deferred = getPage(url) # getPage returns a Deferred
deferred.addCallbacks(success, failure)
deferred.addBoth(stop)
reactor.run()
在這個版本中調用的事件處理函數與之前相同,但它們都註冊到了一個單獨的Deferred對象上,而不是分散在代碼各處再以參數形式傳遞給getPage。
例子1:(簡單的tcp伺服器實現)
server.py
#-*-coding:utf-8-*-
from twisted.internet import protocol,reactor
#from twisted.protocols.basic import LineReceiver
from time import ctime
import os,sys
from twisted.python import log #導入log
PORT = 23233
class TSServerProtocol(protocol.Protocol): #從Protocol派生出的TSSserverProtocol類
def connectionMade(self): #因為繼承了Protocol就可以使用和自定義父類的方法了
clnt = self.clnt = self.transport.getPeer().host
log.msg('Client connected from %s' % clnt) #log用法
#self.sendData()
def dataReceived(self, data): #接受數據的方法
addr = self.transport.getHost().host
if data:
log.msg('Cmd received from %s : %s' % (self.clnt,data)) #data接收到的信息
self.transport.write('這是來自 %s ,的答覆:%s' %(addr,ctime())) #write發送
'''for i in os.listdir(os.getcwd()):
self.transport.write('[%s]%s' %(i,data))'''
def connectionLost(self,reason): #reason參數必須要寫不然報錯,當連接斷開時的調用
log.msg('連接斷開. ')
#log.msg('連接斷開. %s' % reason) # 加上reason會把斷開的錯誤信息答應出來
factory =protocol.Factory() #因為我們上面只導入了protocol,所以這要把Factory函數導進來,每一個protocol的實例都有一個工廠的引用,使用self.factory可以訪問所在的工廠實例
factory.protocol = TSServerProtocol #當有請求進來時調用TSServerProtocol類
print 'waiting for connection......'
log.startLogging(sys.stdout) #以日誌形式列印到視窗
reactor.listenTCP(PORT,factory) #監聽請求
reactor.run() #啟動迴圈
client.py
#-*-coding:utf-8
from twisted.internet import protocol,reactor
HOST = 'localhost' #要連接的IP地址
PORT = 23233 #埠
class TSClntProtocol(protocol.Protocol): #同服務端一樣
def sendData(self): #定義一個發送數據的方法
data = raw_input('>')
if data:
print '....sending %s.......' %data
self.transport.write(data) #發送數據
else:
self.transport.loseConnection() #當沒有輸入時斷開連接
def connectionMade(self):
self.sendData() #調用方法
def dataReceived(self, data):
print data
self.sendData()
class TSClntFactory(protocol.ClientFactory):#我的理解是客戶端寫protocol.ClientFactory,服務端寫protocol.Factory
protocol = TSClntProtocol #同服務端一樣
clientConnectionLost = clientConnectionFailed = lambda self,connector,reason:reactor.stop()
reactor.connectTCP(HOST,PORT,TSClntFactory()) #跟服務端一樣
reactor.run()