витой питон - тайм-аут для отправленного сообщения, которое не получило ответа - PullRequest
3 голосов
/ 28 февраля 2011

Я создаю своего рода реализацию клиент-сервер, и я хотел бы убедиться, что каждое отправленное сообщение получает ответ.Поэтому я хочу создать механизм тайм-аута, который не проверяет, доставлено ли само сообщение, а проверяет, получает ли доставленное сообщение ответ.

IE, для двух компьютеров 1 и 2:

1: send successfully: "hello"
2: <<nothing>>
...
1: Didn't get a response for my "hello" --> timeout

Я подумал об этом, создав большой логический массив с идентификатором для каждого сообщения, который будет содержать флаг «в процессе» и будет установлен при получении ответа на сообщение.

Мне было интересно, возможно, есть лучший способ сделать это.

Спасибо, Идо.

1 Ответ

5 голосов
/ 28 февраля 2011

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

У меня нет 'Я проверил это, это скорее отправная точка.Есть несколько вещей, которые вы можете изменить здесь, чтобы они соответствовали вашим целям:

  1. Я использую LineOnlyReceiver - это не относится к самой проблеме, и вы 'Вам нужно будет заменить sendLine / lineReceived соответствующими вызовами API для вашего протокола.

  2. Это для последовательного соединения, поэтому я не имею дело с connectionLost и т. д.. Возможно, вам потребуется.

  3. Мне нравится сохранять состояние непосредственно в экземпляре.Если вам нужна дополнительная информация о состоянии, установите ее в _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)
...