おっと。私は別のスレッドであなたの質問に答えてくれたかもしれないと思うし、TwistedのUDPフローコントロールのサポートが実際よりも少し強固だと信じさせるかもしれません。にもかかわらず、あなたは何をする必要があるのかを得ることができます...
1.ソケットが書き込み可能になったら、どのメソッドを呼び出しますか?
残念なことに、TwistedのUDPプロトコルは、UDPが常に失敗することを前提として書き込み可能性について監視されないため、EWOULDBLOCK
を発生させることはありません。 Twistedがローカルのワイヤ速度よりも速い速度でUDPを送信している場合にのみ発生します。これは非常に高速なアプリケーションと非常に遅いネットワークを必要とします。
回避策として、アプリケーションには単にEWOULDBLOCK
をキャッチするだけです。他のプロトコルでは、このような回避策が重大な問題になるかもしれませんが、UDPの場合は、すでに送信パケットを失う準備が必要であるため、インバンド制御フローメカニズムが必要です。
that bugからreview processまでのお手伝いは、常にオプションです。
根底にあるソケットが読み取り可能であるとき、あなたはが本当に空想、あなたではなくUDPプロトコルを書いて(自分でIFileDescriptor
を実装することにより)udp.Port
に独自の代替を書くことができ、かつ呼ばれている(doRead
とdoWrite
を上書き取得したい場合それぞれ書き込み可能)。これにより完全な書き込みレベルのフロー制御が可能になりますが、UDPはパケットを時折ドロップし、 "ICMPソースクエンチ"メッセージを適切に処理できないネットワーク上では、おそらく必要ありません。ブロックICMPはブロックされます)、ドロップされたパケットはフロー制御情報のソースのみです。私はTwistedでこのバグを修正するべきではないと言っているわけではありませんが、UDPワールドにおけるこのような事実は、誰もまだそうしたくない理由です。
2.発信UDP帯域幅を特定のデータグラム/秒の量に制限するために特定の時間間隔で呼び出す必要がある場合は、startWriting()メソッドをどのように呼び出す必要がありますか?
この回答のパート1で説明している制限のため、UDPトランスポートには便利なstartWriting
メソッドがありません。
しかし、startWriting
/stopWriting
は、とにかく発信UDP帯域幅をタイムリミットする方法ではありません。
self.transport.write(...)
を、適切なスケジューリングメカニズムを使用してコールをスケジューリングした後、適切なタイミングで呼び出すだけです。たとえば、LoopingCall
は、サウンドサンプルを送信するための適切な間隔でRTPメディアストリーミングのUDP送信を呼び出すように設計されています。しかし、自分の遅延を計算してcallLaterを直接使うこともできます。いずれにしても、UDP経由での転送のためにキューに入れられた発信データの再送信を行う必要がある場合は、何らかのキューメカニズムを使い続ける必要があります。
inboundフロー制御、UDPトランスポートはまだそれを非常にうまくサポートしています(stopReading
とstartReading
)。
この回答が役に立ったと思っています。以前は、この分野でのTwistedの機能について私が誤解してしまった場合、ごめんなさい!
お返事ありがとうございます。 LoopingCallでUDPフロー制御を実装しました。 Looping Callの問題は、UDPパケットが小さい場合(50バイト)、300KBps以上をプッシュできないことです。このテストの間、CPUは最大値になりません。たぶん私はこのLoopingCallコールバックが呼び出されたときにループでwrite()を試みるべきでしょう... –
あなたは、0回のタイムアウトを持つ 'LoopingCall'はハードウェア上で〜6000 UDPパケットをプッシュしますが、 *あなたのCPUを最大限に活用できますか?素朴な 'callLater'ループはどうでしょうか? – Glyph
私はちょうど無限ループでUDP送信を実装し、50バイトパケットで8MBpsしか達成している間にCPUを最大限に活用することができました。まだ多くはありませんが、LoopingCallよりも20倍優れています。おそらく大きなボトルネックはPythonです。 1つのsendto()呼び出しで複数のデータグラムを送ることができればいいです。 –