使用Python Twisted进行UDP流控制
我有一个类,它是从 twisted.internet.protocol.DatagramProtocol
这个类继承而来的。在我的 startProtocol()
方法里,我调用了 startWriting()
,这样每当我可以往套接字写数据而不被阻塞时,它就会收到通知。这里有两个问题:
- 当套接字变得可以写入时,twisted 会调用哪个方法?
- 如果我需要在特定的时间间隔内调用
startWriting()
方法,以限制每秒发送的 UDP 数据包数量,我应该怎么做?
1 个回答
哎呀。我想我可能在另一个讨论中回答了你的问题,让你觉得Twisted对UDP流控制的支持比实际要强大一些。不过,不管怎样,你还是可以完成你需要做的事情……
1. Twisted会在什么情况下调用socket变为可写的方法?
不幸的是,Twisted中的UDP协议并不会监控可写性,因为UDP协议本身就可能随时失败,所以它不应该抛出EWOULDBLOCK
这个错误。(实际上,它有时候确实会抛出,而这是Twisted中的一个bug,我在回答这个问题时又重新发现了这个问题。这种情况只会在Twisted以比本地网络速度更快的速度发送UDP时发生,这需要一个非常快的应用和一个非常慢的网络。)
作为一种解决方法,你的应用可以简单地捕获EWOULDBLOCK
错误。对于其他协议来说,这种解决方法可能会造成严重问题,但对于UDP来说,你本来就得准备好丢失任何发出的数据包,所以你需要一种内部控制流机制。
如果你想要更复杂一点,可以自己写一个替代udp.Port
(通过自己实现IFileDescriptor
),而不是写一个UDP协议,重写doRead
和doWrite
(这两个方法分别在底层socket可读和可写时被调用)。这样你就能实现完美的写入级流控制,但可能并不必要,因为UDP有时会丢失你的数据包,而且在一些无法正确处理“ICMP源抑制”消息的网络上(那些配置为阻止ICMP的简单防火墙会直接阻止这些消息),丢失的数据包就是你唯一的流控制信息。我并不是说你不应该真正修复Twisted中的这个bug,但在UDP的世界里,这种情况可能就是为什么到现在还没有人去修复它的原因。
2. 如果我需要在特定的时间间隔调用startWriting()方法,以限制每秒发送的UDP数据包数量,该怎么做?
由于在第一部分中提到的限制,UDP传输并没有一个有用的startWriting
方法。
不过,startWriting
/stopWriting
其实也不是限制你发送UDP带宽的正确方法。
你只需在适当的时间调用self.transport.write(...)
,并通过合适的调度机制安排这些调用。例如,LoopingCall
就是为了在适当的时间间隔内发送UDP数据而设计的,适合用于RTP媒体流传输。但你也可以自己计算延迟,直接使用callLater。无论如何,你可能需要保留某种队列机制,以防需要重新传输排队等待通过UDP发送的数据,所以只需弹出
如果你需要进行入站流控制,UDP传输在这方面支持得很好,可以使用stopReading
和startReading
。
希望这个回答对你有帮助,如果之前让我误导了你关于Twisted在这方面的能力,我很抱歉!