python twisted - 发送消息无回应时超时
我正在做一个客户端和服务器之间的通信实现,想确保每条发送的消息都有回复。所以我想创建一个超时机制,这个机制不是检查消息是否送达,而是检查送达的消息是否得到了回复。
比如,有两台电脑,1号和2号:
1: send successfully: "hello"
2: <<nothing>>
...
1: Didn't get a response for my "hello" --> timeout
我想通过创建一个大的布尔数组来实现,每条消息都有一个唯一的标识符,这个数组会保存一个“进行中”的标记,当收到消息的回复时,这个标记就会被设置。
我在想,或许还有更好的方法来实现这个功能。
谢谢,
Ido。
1 个回答
5
有一种更好的方法,搞笑的是我自己刚刚在这里实现了这个。它使用了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——这和问题本身没有关系,你需要用适合你协议的API调用来替换
sendLine
/lineReceived
。这是用于串行连接的,所以我没有处理
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)