Есть лучший способ, который, как ни странно, я сам только что реализовал здесь .Он использует 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)