Python中reactor,factory,protocol

最爲簡單的狀況下,除了瞭解清reactor的簡單使用,你還要了解Protocol和Factory。它們最終都會由reactor的偵聽創建和run來統一調度起來。   react

 創建服務器的第一個要解決的問題就是服務與外界的交流協議。協議的定義在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的開發了。服務器

 

1、app

 

protocol:內部實現的主要是鏈接在通訊時的動做;框架

 

         內部有transport,可進行write(), getpeer()(host,port)socket

 

         還有factorytcp

 

 

 

Factory:保存的是鏈接方的信息,當有連接過來時,factory會初始化一個protocol與對方創建鏈接,因此factory中有protocol.  由於protocol的方法常常會用到factory裏的屬性變量,因此protocol類中也有factory。這裏就有一個循環引用的問題,Python中,有些類是有垃圾清理機制的,可是對於那些有定義方法__del__()的類,就會有內存泄露的問題。函數

 

Reactor:是管理twisted框架的核心。全部的事件都會觸發reactor,而後他會開啓服務,初始化factory,factory再初始化protocol。ui

 

Factory和protocol的基礎實如今protocol.py文件中。this

 

 

 

 

 

 

 

2、spa

 

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句柄。

 

 

 

3、繼續深刻:

 

上面講到的是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)

 

 

 

 

 

參照上面的,很清晰了。

相關文章
相關標籤/搜索