Видеть:
Фабрики создают экземпляры протокола.
Это означает, что фабрика будет использовать протокол, чтобы выяснить, как она должна прослушивать и отправлять данные (см. здесь, а также обратите внимание: вы также можете написать свой собственный протокол).
Эти методы доступны для 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): (источник) переопределен в
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
здесь и < href="https://github.com/twisted/twisted/blob/trunk/src/twisted/internet/protocol.py#L120" rel="noreferrer">источник для 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
, когда вызывается метод reactor.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.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)
Который возвращает транспорт, например этот а>:
class Connector(TCPConnector):
def _makeTransport(self):
return Client(self.host, self.port, self.bindAddress, self,
self.reactor)
Что, в свою очередь, создает соединение сокета:
Итак, краткий ответ на ваш вопрос:
Ожидается ли, что отправка сообщений будет реализована независимо от интерфейса протокола?
Protocol
инициализирует transport
значением None, когда реактор вызывает connect
, он устанавливает transport
в экземпляре Protocol
.
Затем реактор использует транспортный объект протоколов для чтения/записи при установлении входящих/исходящих соединений.
Мы можем отправлять данные через сокет tcp с экземпляром Protocol
, используя self.transport.write()
.
Видеть:
person
jmunsch
schedule
08.08.2015
IProcessProtocol
иIProtocol
— разные интерфейсы;IProcessProtocol
получает события от подпроцесса POSIX, порожденногоspawnProcess
, тогда какIProtocol
обрабатывает один поток (обычно из сети). Поскольку это интерфейсы для получения потоков данных, сообщения являются более высокого уровня и обрабатываются в другом месте. Но неясно, что вы на самом деле спрашиваете о том, как отправлять сообщения, или чего вы не находите в документации. - person Glyph   schedule 08.08.2015