我正在写一个实现自定义协议的客户端,并且有一个工厂。我的问题如下:我的客户进行双向通讯,有时我想告诉它“发送此数据”。但是我所拥有的只是工厂对象:
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)
因此,我创建了一个工厂并拥有一个工厂对象,但我没有协议对象。send_message调用上述方法时,我得到一个错误,因为self.protocol它只是一个类,而不是一个对象。
send_message
self.protocol
我怎样才能做到这一点?除了工厂之外,我还应该公开连接协议吗?
谢谢
您可以访问所需的所有对象。工厂负责创建协议实例,因此,如果要将协议实例保留在工厂可以使用的位置,请覆盖buildProtocol并保存该实例:
buildProtocol
class MyFactory(ClientFactory): protocol = MyProtocol ... def buildProtocol(self, address): proto = ClientFactory.buildProtocol(self, address) self.connectedProtocol = proto return proto
但是,这种方法缺少一个重要功能。很难说出何时buildProtocol已调用和connectedProtocol已设置。如果尝试天真使用此属性:
connectedProtocol
factory = MyFactory() reactor.connectTCP(host, port, factory) factory.connectedProtocol.send_message(...)
代码将失败并显示,AttributeError因为尚未实际建立连接。由于Twisted是事件驱动的,因此您需要通过响应表示已建立连接的事件来确保使用此代码。
AttributeError
您可以通过在构造协议时触发回调来完成此操作,而不仅仅是设置属性。Twisted实际上有一个帮助工厂,它已经做了这样的事情:
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)
你也可以保存在参考connectedProtocol的cbConnected回调,这样就可以在以后继续使用它。您还可以在中开始任何其他要使用连接的协议的操作cbConnected,以便他们在实际可用之前不要尝试使用连接。
cbConnected