扭曲的python工厂和协议接口如何工作?

Pip*_*ppi 5 python twisted twisted.web twisted.internet

我正在学习Twisted,初学者的教程经常使用Factory和Protocol作为示例.工厂和协议接口似乎不支持发送消息.是否期望发送消息独立于协议接口实现?

class IProcessProtocol(Interface):
    def makeConnection(process):
    def childDataReceived(childFD, data):
    def childConnectionLost(childFD):
    def processExited(reason):
    def processEnded(reason):
Run Code Online (Sandbox Code Playgroud)

jmu*_*sch 17

看到:

工厂创建协议实例.

这意味着工厂将使用该协议来确定它应该如何监听和发送数据(参见 此处并注意:您也可以编写自己的协议).

以下是可用于Protocol以下方法的方法:

Method  logPrefix Return a prefix matching the class name, to identify log messages related to this protocol instance.
Method  dataReceived  Called whenever data is received.
Method  connectionLost  Called when the connection is shut down.
Run Code Online (Sandbox Code Playgroud)

继承自BaseProtocol:

Method  makeConnection  Make a connection to a transport and a server.
Method  connectionMade  Called when a
Run Code Online (Sandbox Code Playgroud)

连接.

一旦建立了连接,我们就可以执行类似写入数据的操作transport:

from twisted.internet.protocol import Protocol
class SomeProtocol(Protocol):
    def dataReceived(self, data):
        print('Do something with data: {}'.format(data))

    def connectionMade(self):
        self.transport.write("Hello there")
Run Code Online (Sandbox Code Playgroud)

但等待在什么地方Protocol获取self.transport的呢?

>>> from twisted.internet.protocol import Protocol, BaseProtocol
>>> import inspect
>>> from pprint import pprint
>>> pprint(inspect.getclasstree(inspect.getmro(Protocol)))
[(<class 'object'>, ()),
 [(<class 'twisted.internet.protocol.BaseProtocol'>, (<class 'object'>,)),
  [(<class 'twisted.internet.protocol.Protocol'>,
    (<class 'twisted.internet.protocol.BaseProtocol'>,))]]]
>>> dir(Protocol)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', 
 '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', 
 '__hash__', '__implemented__', '__init__', '__le__', '__lt__', 
 '__module__', '__ne__', '__new__', '__providedBy__', '__provides__', 
 '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', 
 '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 
 'connected', 'connectionLost', 'connectionMade', 'dataReceived', 
 'logPrefix', 'makeConnection', 'transport']
Run Code Online (Sandbox Code Playgroud)

好的,Protocol有一个transport对象/方法怎么样BaseProtocol:

>>> dir(BaseProtocol)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__',           
 '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', 
 '__hash__', '__implemented__', '__init__', '__le__', '__lt__', 
 '__module__', '__ne__', '__new__', '__providedBy__', '__provides__', 
 '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', 
 '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 
 'connected', 'connectionMade', 'makeConnection', 'transport']
>>> type(BaseProtocol.transport)
<class 'NoneType'>
Run Code Online (Sandbox Code Playgroud)

这是为什么呢None

所以让我们看看BaseProtocol 这里:

def makeConnection(self,transport):( source)重写

twisted.internet.endpoints._WrapIProtocol,
twisted.protocols.amp.BinaryBoxProtocol,
twisted.protocols.basic.NetstringReceiver,
twisted.protocols.ftp.ProtocolWrapper,
twisted.protocols.ftp.SenderProtocol,
twisted.protocols.policies.ProtocolWrapper,
twisted.protocols.stateful.StatefulProtocol Make a connection to a
transport and a server.
Run Code Online (Sandbox Code Playgroud)

注意:

This sets the 'transport' attribute of this
Protocol, and calls the connectionMade() callback.
Run Code Online (Sandbox Code Playgroud)

因此,当makeConnection调用它时,它会设置transport协议的属性.

那么这对工厂有何影响?

让我们来看看在Factory 这里buildProtocol

def buildProtocol(self, addr):
    """
    Create an instance of a subclass of Protocol.

    The returned instance will handle input on an incoming server
    connection, and an attribute "factory" pointing to the creating
    factory.

    Alternatively, C{None} may be returned to immediately close the
    new connection.

    Override this method to alter how Protocol instances get created.

    @param addr: an object implementing L{twisted.internet.interfaces.IAddress}
    """
    p = self.protocol()
    p.factory = self
    return p
Run Code Online (Sandbox Code Playgroud)

可以,然后呢:

class BaseProtocol:
    """
    This is the abstract superclass of all protocols.

    Some methods have helpful default implementations here so that they can
    easily be shared, but otherwise the direct subclasses of this class are more
    interesting, L{Protocol} and L{ProcessProtocol}.
    """
    connected = 0
    transport = None

    def makeConnection(self, transport):
        """Make a connection to a transport and a server.

        This sets the 'transport' attribute of this Protocol, and calls the
        connectionMade() callback.
        """
        self.connected = 1
        self.transport = transport
        self.connectionMade()
Run Code Online (Sandbox Code Playgroud)

因此传输在这里定义为None,但仍然transport来自哪里?

它来自于调用方法reactorreactor.connect.

让我们看一个TCP示例:

from twisted.internet import reactor
# 
#
#
reactor.connectTCP('localhost', 80, SomeProtocolFactory())
Run Code Online (Sandbox Code Playgroud)

reactor我们称之为connectTCP这样:

from twisted.internet.iocpreactor import tcp, udp
#
#
#
def connectTCP(self, host, port, factory, timeout=30, bindAddress=None):
    """
    @see: twisted.internet.interfaces.IReactorTCP.connectTCP
    """
    c = tcp.Connector(host, port, factory, timeout, bindAddress, self)
    c.connect()
    return c
Run Code Online (Sandbox Code Playgroud)

这是调用tcp.Connector喜欢from twisted.internet.iocpreactor import tcp, udp 这里:

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
    ##################
    # ah here we are
    ##################
    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)
Run Code Online (Sandbox Code Playgroud)

这是返回,如运输这样:

class Connector(TCPConnector):
    def _makeTransport(self):
        return Client(self.host, self.port, self.bindAddress, self,
                      self.reactor)
Run Code Online (Sandbox Code Playgroud)

这反过来又创建了套接字连接:

所以简短回答你的问题:

是否期望发送消息独立于协议接口实现?

Protocol初始化transport为无,当反应器调用connect它设置transportProtocol实例.

然后,当进行传入/传出连接时,反应器使用协议传输对象进行读/写.

我们可以Protocol通过使用实例通过tcp套接字发送数据self.transport.write().

看到: