5

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

class IProcessProtocol(Interface):
    def makeConnection(process):
    def childDataReceived(childFD, data):
    def childConnectionLost(childFD):
    def processExited(reason):
    def processEnded(reason):
4

1 回答 1

20

看:

工厂创建协议实例。

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

这些是可用的方法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.

继承自 BaseProtocol:

Method  makeConnection  Make a connection to a transport and a server.
Method  connectionMade  Called when a

建立连接。

一旦建立连接,我们就可以做一些事情,比如将数据写入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")

但是等等从哪里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']

好的,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'>

它为什么会这样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.

笔记:

This sets the 'transport' attribute of this
Protocol, and calls the connectionMade() callback.

所以当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

可以,然后呢:

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()

所以运输在这里被定义为无,但仍然transport来自哪里?

它来自调用reactorreactor.connect方法的时间。

让我们看一个 TCP 示例:

from twisted.internet import reactor
# 
#
#
reactor.connectTCP('localhost', 80, SomeProtocolFactory())

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

tcp.Connectorfrom 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)

这样返回运输:

class Connector(TCPConnector):
    def _makeTransport(self):
        return Client(self.host, self.port, self.bindAddress, self,
                      self.reactor)

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

所以对你的问题的简短回答:

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

当反应器在实例上调用它时,Protocol初始化为 None。transportconnecttransportProtocol

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

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

看:

于 2015-08-08T03:57:02.983 回答