python - Twisted python Factory 和 Protocol 接口(interface)如何工作?

标签 python twisted twisted.web twisted.internet

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

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

最佳答案

参见:

工厂创建协议(protocol)实例。

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

这些是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

connection is made.

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

def makeConnection(self, transport): (source) overridden in

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 被调用时,它会设置协议(protocol)的 transport 属性。

那么工厂是如何运作的呢?

让我们看一个Factory heresource对于 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()

所以传输在这里定义为 None,但是 transport 还是从哪里来的呢?

当调用 reactor.connect 方法时,它来自 reactor

让我们看一个 TCP 示例:

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

我们从reactor 调用connectTCP,如this :

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.Connector 就像 from twisted.internet.iocpreactor import tcp, udp here :

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)

它正在返回类似 this 的传输:

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

依次创建套接字连接:

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

Is it expected that sending messages are implemented independently of Protocol interface?

Protocoltransport 初始化为None,当reactor 调用connect 时,它会在 上设置transport >协议(protocol)实例。

react 器然后使用协议(protocol)传输对象在建立传入/传出连接时进行读/写。

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

参见:

关于python - Twisted python Factory 和 Protocol 接口(interface)如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31888037/

相关文章:

python - Lambda 评估意外

python扭曲和多处理

javascript - 使用 strope 进行 facebook 聊天,旁遮普语

python - 扭曲的非阻塞方法——如何实现?

python - 扭曲和 Websockets : Beyond Echo

python - 扭曲多个并发或异步流

python - 在python中没有类的碰撞矩形

Python 和历史扩展

python - 属性错误 : 'module' object has no attribute 'OP_NO_TLSv1_1

javascript - 网站 : Send data from javascript (client) to python (server)