【问题标题】:Set a timeout for an UDP socket with Twisted (python)使用 Twisted (python) 为 UDP 套接字设置超时
【发布时间】:2015-06-17 12:41:46
【问题描述】:

我在 python 程序中使用 Twisted。我每分钟发送一次数据并在 UDP 套接字上接收数据,我需要设置一个超时时间。

我找到了一种方法来做到这一点,但我想知道这是否是一种好方法。

这是我的代码的想法:

class UDPSocket(DatagramProtocol):
   def startProtocol(self):
       self.transport.connect(self.HOST, self.PORT)
       reactor.callLater(1, self.send_data)

   def send_data(self):
       reactor.callLater(60, self.send_data)
       self.transport.write("Some data")
       self.timeoutCallId = reactor.callLater(5, raise_timeout)

   def datagramReceived(self, data, (host, port)):
       if self.timeoutCallId.active():
           self.timeoutCallId.cancel()
       #Do something with data

   def raise_timeout(self):
       #Do something to manage timeout

reactor.listenUDP(port, UDPSocket())
reactor.run()

感谢您的建议

编辑:

它有效,但我有一个问题。

如果发生超时,我会正确地进入 raise_timeout 函数,但是当调用下一个“send_data()”时,self.transport.write("data") 函数会引发异常: “NoneType”对象没有“写”属性。

我猜 self.transport 已断开连接。

我该如何解决这个问题?

【问题讨论】:

  • "这是个好主意吗?" -- 这取决于您的特定用例,不是吗?
  • 我只想生成一个超时。就像套接字库一样,当我们使用“socket.settimeout(5)”在我们执行“socket.recvfrom(1024)”时引发超时错误
  • 超时的目的是什么?如果我们在 x 时间内没有收到确认,我们会提出超时并中止?这不是 TCP 吗?
  • 就我而言,TCP 是绝对不可能的。超时的目的正如您所解释的那样。如果我在发送数据 5 秒后没有收到 ACK,我需要引发超时以通知我的应用程序数据包丢失。
  • 您可能还需要更智能地处理timeoutCallId。例如,两次取消单个调用是错误的 - 如果您收到两个数据报,这就是当前发生的情况。

标签: python sockets twisted


【解决方案1】:

我找到了解决办法。

当我们使用UDP时,当我们发送一个数据报时,如果不到1秒没有收到回复,“self.transport”设置为None并调用“stopProtocol”方法。一旦我们离开“stopProtocol”方法,reactor 就会停止监听指定的 UDP 端口。

这是我的解决方案代码:

class UDPSocket(DatagramProtocol):
    def __init__(self, mainreactor):
        self._reactor = mainreactor

    def startListenUDP(self):
        try :
            self._reactor.listenUDP(KeepAlive.PORT, self)
        except Exception, e :
            pass

    def startProtocol(self) :
        self.transport.connect(self.host, self.port)

    def stopProtocol(self):
        print "Transport disconnected !"
        self._reactor.callLater(0.1, self.startListenUDP)

    def raise_timeout(self) :
        print "Timeout !"

    def datagramReceived(self, datagram, host):
        try :
            if self.timeout_id.active():
                self.timeout_id.cancel()
        except Exception, e :
            pass
        print datagram

    def sendDatagram(self):
        datagram = "Some Data"
        try :
            self.transport.write(datagram)
            self.timeout_id = self._reactor.callLater(TIMEOUT, 
                self.raise_timeout)
        except Exception, e :
            self._reactor.callLater(0.1, self.startListenUDP)

def main():
    protocol = UDPSocket(reactor)
    t = reactor.listenUDP(PORT, protocol)
    l = task.LoopingCall(protocol.sendDatagram)
    l.start(60)
    reactor.run()

#MAIN
if __name__ == '__main__':
    main()

【讨论】:

    猜你喜欢
    • 2012-11-12
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-12
    相关资源
    最近更新 更多