Twisted python Factory 和 Protocol 接口如何工作?
How do Twisted python Factory and Protocol interfaces work?
我正在学习Twisted,初学者的tutorial often uses Factory and Protocol as examples. It appears that Factory and Protocol界面不支持发送消息。是否期望发送消息独立于协议接口实现?
class IProcessProtocol(Interface):
def makeConnection(process):
def childDataReceived(childFD, data):
def childConnectionLost(childFD):
def processExited(reason):
def processEnded(reason):
参见:
- http://twistedmatrix.com/documents/current/api/twisted.internet.protocol.Factory.html
- http://twistedmatrix.com/documents/current/api/twisted.internet.protocol.html
工厂创建协议实例。
这意味着工厂将使用协议来确定它应该如何监听和发送数据(参见 here 另请注意:您也可以编写自己的协议)。
这些是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
object/method 那么 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
时,它会设置协议的 transport
属性。
那么工厂是如何工作的?
让我们看一个 Factory
here and the source for 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?
Protocol
将 transport
初始化为 None,当反应器调用 connect
时,它会在 Protocol
实例上设置 transport
。
当建立 incoming/outgoing 连接时,反应堆然后使用协议传输对象到 read/write。
我们可以使用 self.transport.write()
.
通过 Protocol
实例通过 tcp 套接字发送数据
参见:
- how to send data with twisted protocol via factory
我正在学习Twisted,初学者的tutorial often uses Factory and Protocol as examples. It appears that Factory and Protocol界面不支持发送消息。是否期望发送消息独立于协议接口实现?
class IProcessProtocol(Interface):
def makeConnection(process):
def childDataReceived(childFD, data):
def childConnectionLost(childFD):
def processExited(reason):
def processEnded(reason):
参见:
- http://twistedmatrix.com/documents/current/api/twisted.internet.protocol.Factory.html
- http://twistedmatrix.com/documents/current/api/twisted.internet.protocol.html
工厂创建协议实例。
这意味着工厂将使用协议来确定它应该如何监听和发送数据(参见 here 另请注意:您也可以编写自己的协议)。
这些是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
object/method 那么 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
时,它会设置协议的 transport
属性。
那么工厂是如何工作的?
让我们看一个 Factory
here and the source for 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?
Protocol
将 transport
初始化为 None,当反应器调用 connect
时,它会在 Protocol
实例上设置 transport
。
当建立 incoming/outgoing 连接时,反应堆然后使用协议传输对象到 read/write。
我们可以使用 self.transport.write()
.
Protocol
实例通过 tcp 套接字发送数据
参见:
- how to send data with twisted protocol via factory