有一个更好的方法,有趣的是我自己just implemented here。它使用TimeoutMixin 来实现您需要的超时行为,并使用DeferredLock 来匹配正确的回复与发送的内容。
from twisted.internet import defer
from twisted.protocols.policies import TimeoutMixin
from twisted.protocols.basic import LineOnlyReceiver
class PingPongProtocol(LineOnlyReceiver, TimeoutMixin):
def __init__(self):
self.lock = defer.DeferredLock()
self.deferred = None
def sendMessage(self, msg):
result = self.lock.run(self._doSend, msg)
return result
def _doSend(self, msg):
assert self.deferred is None, "Already waiting for reply!"
self.deferred = defer.Deferred()
self.deferred.addBoth(self._cleanup)
self.setTimeout(self.DEFAULT_TIMEOUT)
self.sendLine(msg)
return self.deferred
def _cleanup(self, res):
self.deferred = None
return res
def lineReceived(self, line):
if self.deferred:
self.setTimeout(None)
self.deferred.callback(line)
# If not, we've timed out or this is a spurious line
def timeoutConnection(self):
self.deferred.errback(
Timeout("Some informative message"))
我没有对此进行测试,这更像是一个起点。您可能需要在此处更改一些内容以满足您的目的:
-
我使用 LineOnlyReceiver — 这与问题本身无关,您需要将 sendLine/lineReceived 替换为适合您协议的 API 调用。
李>
这是用于串行连接的,所以我不处理connectionLost 等。您可能需要。
我喜欢将状态直接保存在实例中。如果您需要额外的状态信息,请在_doSend 中设置它并在_cleanup 中清理它。有些人不喜欢这样——另一种方法是在_doSend 中创建嵌套函数,以关闭您需要的状态信息。你仍然需要那个self.deferred,否则lineReceived(或dataReceived)不知道该怎么做。
如何使用
就像我说的,我为串行通信创建了这个,我不必担心工厂、connectTCP 等。如果您使用 TCP 通信,则需要找出所需的额外粘合剂。
# Create the protocol somehow. Maybe this actually happens in a factory,
# in which case, the factory could have wrapper methods for this.
protocol = PingPongProtocol()
def = protocol.sendMessage("Hi there!")
def.addCallbacks(gotHiResponse, noHiResponse)