標籤:
最為簡單的情況下,除了瞭解清reactor的簡單使用,你還要瞭解Protocol和Factory。它們最終都會由reactor的偵聽建立和run來統一調度起來。
建立伺服器的第一個要解決的問題就是服務與外界的交流協議。協議的定義在twisted中是通過繼承twisted.internet.protocol.Protocol類來實現的。在協議中你可以定義串連、資料接收、中斷連線等一系列的事件如果進行響應。但是對於所有串連上來的協議的建立、持久配置資料的儲存這樣的內容並不會儲存在協議中。
持久配置資料的儲存通常都會儲存在工廠裡。
工廠的定義在twisted中是通過繼承twisted.internet.protocol.Factory類來實現的。twisted提供了預設的工廠實現最為普通的需求。它會執行個體化每個協議,並且通過設定每個協議中factory屬性來使協議可以使用到它自己,做這個設定的作用就是讓協議在進行處理串連資料時可以使用到工廠中儲存的持久配置資料。工廠的啟動是需要reactor真實的建立偵聽並啟動才可以實現的。
reactor偵聽的建立可以參考 twisted.internet.interfaces.IReactorTCP.listenTCP。這時我們先只說建立TCP伺服器的偵聽,如果你需要其它種類的偵聽建立參考IReactor*.listen*系列API。
總結一下,我們書寫一個twisted的Daemon,實質上會關注三個層次的對象。它們互相可配置,可獨立開發,只需要通過簡單的調用配置就可結合使用。第一層次就是偵聽的建立、工廠的初始化、伺服器的運行,它需要reactor的開發。第二個層次就是服務的初始化、使用者串連的建立、持久配置資料的儲存、協議的執行個體化,它需要factory的開發。第三個層次就是使用者串連建立後的事件處理,這就需要protocol的開發了。
一、
protocol:內部實現的主要是串連在通訊時的動作;
內部有transport,可進行write(), getpeer()(host,port)
還有factory
Factory:儲存的是串連方的資訊,當有連結過來時,factory會初始化一個protocol與對方建立串連,所以factory中有protocol. 因為protocol的方法經常會用到factory裡的屬性變數,所以protocol類中也有factory。這裡就有一個循環參考的問題,Python中,有些類是有垃圾清理機制的,但是對於那些有定義方法__del__()的類,就會有記憶體泄露的問題。
Reactor:是管理twisted架構的核心。所有的事件都會觸發reactor,然後他會開啟服務,初始化factory,factory再初始化protocol。
Factory和protocol的基礎實現在protocol.py檔案中。
二、
Reactor:
是twisted架構中很重要的概念,事件驅動。他負責監測所有事件。
最常用的是run(), stop(), callLater()
callLater()實際是執行個體化了一個DelayedCall()類,並將執行個體的控制代碼返回。可進行cancel(), reset(), delay()等操作。
Reactor的實現,應該繼承了internet\base.py檔案中的類ReactorBase(object)還有類_SignalReactorMixin,其中,_SignalReactorMixin類中有定義run()函數。
ReactorBase(object)類中,有方法stop()。好多reactor和thread的操作函數也能在這裡面找到,上面的callLater()就是在這裡實現的。
在internet\posixbase.py檔案中,有類PosixReactorBase(_SignalReactorMixin, ReactorBase),是上面說到的兩個類的繼承。在這裡,實現了各種listen**函數,主要服務員server;還有對應的connect**函數,針對client。
<一>、例如:用戶端可以使用:reactor. connectTCP(self, host, port, factory, timeout=30, bindAddress=None)
這是一個直接可以用的,所以reactor必定繼承自PosixReactorBase。
在connectTCP()中,實現如下:
c = tcp.Connector(host, port, factory, timeout, bindAddress, self)
c.connect()
return c
第一句:執行個體一個tcp.Connector類,該類繼承自base. BaseConnector;
類base. BaseConnector實現的方法有:disconnect(), connect(),stopConnecting(self), cancelTimeout(self), buildProtocol(self, addr), connectionFailed(self, reason), connectionLost(self, reason)…
這些方法,和factory中的方法,函數名很相似,其實這些函數的內部就是調用相應的factory方法的。該類中有個很重要的變數就是self.factory。
第二句:是串連的發起函數,主要是開啟了factory(connectTCP函數中傳入的)。
Connect()定義如下:
def connect(self):
"""Start connection to remote server."""
if self.state != "disconnected":
raise RuntimeError, "can‘t connect in this state"
self.state = "connecting"
if not self.factoryStarted:
self.factory.doStart()
self.factoryStarted = 1
self.transport = transport = self._makeTransport()
if self.timeout is not None:
self.timeoutID = self.reactor.callLater(self.timeout, transport.failIfNotConnected, error.TimeoutError())
self.factory.startedConnecting(self)
進過上面分析,reactor, factory, protocol就聯絡到一起了,很多操作也就清晰了。再回過去讀最前面引用的內容,應該好理解多了。
<二>、對於服務端:reactor. listenTCP(self, port, factory, backlog=50, interface=‘‘)
具體實現如下:
p = tcp.Port(port, factory, backlog, interface, self)
p.startListening()
return p
第一句:執行個體一個tcp.Port類,該類繼承了base.BasePort, _SocketCloser。
實現的方法有:
createInternetSocket(self),startListening(self),_buildAddr(self, (host, port)),
doRead(self),connectionLost(self, reason),getHost(self),doWrite(self)
loseConnection(self, connDone=failure.Failure(main.CONNECTION_DONE))
也有self.factory變數
第二句:做必要的準備,如:create and bind socket,偵聽連接埠,讀取資料等。
def startListening(self):
"""Create and bind my socket, and begin listening on it.
This is called on unserialization, and must be called after creating a
server to begin listening on the specified port.
"""
try:
skt = self.createInternetSocket()
skt.bind((self.interface, self.port))
except socket.error, le:
raise CannotListenError, (self.interface, self.port, le)
# Make sure that if we listened on port 0, we update that to
# reflect what the OS actually assigned us.
self._realPortNumber = skt.getsockname()[1]
log.msg("%s starting on %s" % (self.factory.__class__, self._realPortNumber))
# The order of the next 6 lines is kind of bizarre. If no one
# can explain it, perhaps we should re-arrange them.
self.factory.doStart()
skt.listen(self.backlog)
self.connected = True
self.socket = skt
self.fileno = self.socket.fileno
self.numberAccepts = 100
self.startReading()
其中skt是socket.socket()返回的socket控制代碼。
三、繼續深入:
上面講到的是reactor.connectTCP(),這個方法會直接開始工作的(初始化factory,protocol等),也許我們需要自己手工控制這個過程。下面是利用類去實現:
\appliction\internet.py檔案中的,類TCPClient,當時為了找到這個類名,花了很多時間,這個類名是通過組合而成。
其原型是:class _AbstractClient(_VolatileDataService)
還有class _AbstractServer(_VolatileDataService)作為服務端的原型
一下幾個類均是上面兩個類的一個模式:
TCPServer, TCPClient,
UNIXServer, UNIXClient,
SSLServer, SSLClient,
UDPServer, UDPClient,
UNIXDatagramServer, UNIXDatagramClient,
MulticastServer
class _AbstractClient和class _AbstractServer最終都是從\appliction\server.py中Server繼承而來的。兩個類都是服務,只是在實現過程稍有差別,一個針對connect,一個針對port。
它們均有:
self.reactor,是通過參數傳遞進去的。
Self.method,儲存的是串連的方式,如tcp,udp
self._connection,儲存串連的(其實是上面的listen**或connect**的傳回值)
已經執行個體了對象,如何開始服務(工作)呢? startService(self)
1)、先來看看class _AbstractServer中的:
def startService(self):
service.Service.startService(self)
if self._port is None:
self._port = self._getPort()
def _getPort(self):
"""
Wrapper around the appropriate listen method of the reactor.
@return: the port object returned by the listen method.
@rtype: an object providing L{IListeningPort}.
"""
if self.reactor is None:
from twisted.internet import reactor
else:
eactor = self.reactor
return getattr(reactor, ‘listen%s‘ % (self.method,))(
*self.args, **self.kwargs)
Getattr()這個函數不錯,呵呵
最終調用的還是reactor中的linsten**,但是經過是先定義一個server,再通過server.startServer()開啟的。
2)、再來看看class _AbstractClient
def startService(self):
service.Service.startService(self)
self._connection = self._getConnection()
def _getConnection(self):
"""
Wrapper around the appropriate connect method of the reactor.
@return: the port object returned by the connect method.
@rtype: an object providing L{IConnector}.
"""
if self.reactor is None:
from twisted.internet import reactor
else:
reactor = self.reactor
return getattr(reactor, ‘connect%s‘ % (self.method,))(
*self.args, **self.kwargs)
參照上面的,很清晰了。
Python中reactor,factory,protocol