2011-10-26 134 views
3

我有一个类继承twisted.internet.protocol.DatagramProtocol类。在我的startProtocol()实现中,我调用startWriting(),以便每次我可以写入时通知套接字而不会阻塞。两个问题:UDP流量控制与Python Twisted

  1. 什么样的方法将调用一次套接字将变为可写?
  2. 如果需要在特定的时间间隔上调用startWriting()方法来限制外出UDP带宽为特定的数据报/秒数,我应该如何调用startWriting()方法?

回答

2

糟糕。我想我可能已经在另一个线程中回答了您的问题,并且让您相信Twisted中的UDP流量控制支持比实际上更强大一些。尽管如此,你可以得到你需要做的事情...

1.哪种方法将Twisted调用一次套接字将变成可写?

不幸的是,Twisted中的UDP协议在可写性方面没有得到监控,前提是UDP总是可能失败,所以它永远不应该升起EWOULDBLOCK。 (除了实际上,它有时和我刚刚在回答这个问题时重新发现的this is a bug in Twisted这只发生在Twisted以比本地线速度更快的速度发送UDP时,这需要非常快的应用程序和非常慢的网络。)

作为解决方法,您的应用程序可以简单地捕获EWOULDBLOCK。对于任何其他协议,此类解决方案可能构成严重问题,但对于UDP,您必须准备好丢失任何传出数据包,因此无论如何您都需要带内控制流程机制。

通过review process帮助我们获得that bug始终是一种选择。

如果你想获得真的花哨,您可以编写自己的替代udp.Port(自行实施IFileDescriptor),而不是写一个UDP协议,并覆盖doReaddoWrite(被称为当标的插座是可读和分别可写)。这将为您提供完美的写入级流量控制,但可能不是必需的,因为UDP有时会丢弃数据包,并且在网络上无法正确处理“ICMP源熄灭”消息(将默认的防火墙配置为块ICMP就会阻塞),丢包是你的流量控制信息的来源只有。我并不是说你不应该在Twisted中纠正这个错误,但是这个UDP世界中的生活事实可能是没人愿意这么做的原因。

2.如果需要在特定时间间隔上调用startWriting()方法以限制传出UDP带宽为特定数据报/秒数,我应该如何调用startWriting()方法?

由于本答案的第1部分中描述的限制,UDP传输没有有用的startWriting方法。

但是,startWriting/stopWriting不是真的正确的方式来限制你的出站UDP带宽无论如何。

在通过适当的调度机制调度所述调用之后,在适当的时间简单地呼叫self.transport.write(...)。例如,设计用于以合适的间隔为发送声音样本调用用于RTP媒体流的UDP发送。但你也可以直接计算自己的延迟并使用callLater。在任何情况下,如果您需要对通过UDP传输排队的传出数据进行任何重新传输,您可能需要保留某种队列机制,因此只需弹出

如果您需要执行入站流量控制,UDP传输仍然支持,很好,stopReadingstartReading

希望这个答案是有帮助的,如果我以前误导了你关于Twisted在这个领域的能力,对不起!

+1

感谢您的回答。我使用LoopingCall实现了UDP流量控制。 Looping Call的问题是,当UDP数据包很小(50字节)时,它不能推送超过300KBps。在此测试期间,CPU没有被刷新。当这个LoopingCall回调被调用时,也许我应该尝试在一个循环中执行write()...... –

+0

你说'LoopingCall'具有0超时只会在硬件上每秒推送〜6000个UDP数据包,但不会* *最大限度地减少你的CPU?天真的'callLater'循环怎么样? – Glyph

+1

我刚刚在一个紧密的无限循环中实现了UDP发送,并且能够最大限度地利用CPU,同时仍然以50字节的数据包实现8MBps。仍然不是很多,但比LoopingCall好20倍。这里最大的瓶颈很可能是Python。如果我可以用一个sendto()调用发送多个数据报,那将会很好。 –