how to send data with twisted protocol via factory

I'm writing a client implementing a custom protocol, and have a factory for it. My problem is the following: my client has bi-dir communication, and sometimes I want to tell it "send this data". But all I have is the factory object:

class MyFactory(ClientFactory):
    protocol = MyProtocol

    def __init__(self, recv_callback):
        self.recv_callback = recv_callback

    def send_message(self, msg):
        self.protocol.send_message(msg)

So I create a factory and have a factory object, I don't the protocol object. When send_message above is called I get an error because self.protocol is just a class, not an object.

How can I do this? Should I also expose the protocol for connection in addition to the factory?

Thanks


You have access to all of the objects you want. The factory is responsible for creating protocol instances, so if you want to keep the protocol instance around where the factory can use it, override buildProtocol and save the instance:

class MyFactory(ClientFactory):
    protocol = MyProtocol

    ...

    def buildProtocol(self, address):
        proto = ClientFactory.buildProtocol(self, address)
        self.connectedProtocol = proto
        return proto

However, this approach is lacking in one important feature. It does not make it easy to tell when buildProtocol has been called and connectedProtocol has been set. If you try to use this attribute naively:

factory = MyFactory()
reactor.connectTCP(host, port, factory)
factory.connectedProtocol.send_message(...)

The code will fail with an AttributeError because the connection has not yet actually been set up. Since Twisted is event driven, you need to make sure to use this code by responding to an event that says the connection has been set up.

You might do this by firing a callback when the protocol is constructed instead of just setting an attribute. Twisted actually has a helper factory which does something like this already:

from twisted.internet.protocol import ClientCreator

cc = ClientCreator(reactor, MyProtocol)
whenConnected = cc.connectTCP(host, port)

# Or the equivalent with endpoints
#  from twisted.internet.endpoints import TCP4ClientEndpoint
#  from twisted.internet.protocol import ClientFactory
#  endpoint = TCP4ClientEndpoint(reactor, host, port)
#  factory = ClientFactory()
#  factory.protocol = MyProtocol
#  whenConnected = endpoint.connect(factory)

def cbConnected(connectedProtocol):
    connectedProtocol.send_message(...)

def ebConnectError(reason):
    # Connection attempt failed, perhaps retry
    ...

whenConnected.addCallbacks(cbConnected, ebConnectError)

You could also save the reference to connectedProtocol in the cbConnected callback so that you can continue to use it later on. You might also start whatever other operations want to use the connected protocol in cbConnected , so that they don't try to use the connection before it is actually available.

链接地址: http://www.djcxy.com/p/29202.html

上一篇: 扭曲:禁用Twisted的日志记录

下一篇: 如何通过工厂以扭曲协议发送数据