BSDソケットを使用してクライアントサーバーアプリを作成しています。バックグラウンドで実行し、データを継続的に転送する必要がありますが、通常の使用からネットワークインターフェイスの帯域幅を占有することはできません。インターフェイスの速度に応じて、この接続を特定の最大転送速度に調整する必要があります。
プログラムでこれを達成するための最良の方法は何ですか?
BSDソケットを使用してクライアントサーバーアプリを作成しています。バックグラウンドで実行し、データを継続的に転送する必要がありますが、通常の使用からネットワークインターフェイスの帯域幅を占有することはできません。インターフェイスの速度に応じて、この接続を特定の最大転送速度に調整する必要があります。
プログラムでこれを達成するための最良の方法は何ですか?
各転送後に一定量の 1 秒間スリープすると、ネットワーク パフォーマンスが不安定になるという問題があります。
BandwidthMaxThreshold を目的の帯域幅しきい値にします。
TransferRate を接続の現在の転送速度とします。
それで...
TransferRate > BandwidthMaxThreshold を検出した場合は、SleepTime = 1 + SleepTime * 1.02 を実行します (スリープ時間を 2% 増やします)。
各ネットワーク操作の前後に Sleep(SleepTime) を実行します
TransferRate が BandwidthMaxThreshold よりもはるかに低いことがわかった場合は、SleepTime を減らすことができます。または、SleepTime を常に時間の経過とともに減衰/減少させることもできます。最終的に、SleepTime は再び 0 になります。
2% の増加の代わりに、TransferRate - BandwidthMaxThreshold の差を直線的により多く増加させることもできます。
ユーザーのネットワークが希望するほど高くない場合はスリープしないため、この解決策は適切です。
最良の方法は、トークン バケットを使用することです。
パケットを満たすのに十分なトークンがある場合にのみ送信します (1460 バイトが適切な量です)。受信側の場合は、十分なトークンがある場合にのみソケットから読み取ります。少し簡単な計算をすると、十分なトークンが得られるまでにどれくらい待たなければならないかがわかるので、その時間だけスリープできます (ほとんどのオペレーティング システムはあなたが要求したよりも長くプロセスをスリープさせます)。
バーストのサイズを制御するには、所有できるトークンの最大量を制限します。適切な量は、1 秒分のトークンである可能性があります。
私はトリクルで幸運を祈りました。任意のユーザースペースアプリケーションを変更せずに調整できるので、すばらしいです。帯域幅の計算を行う独自のsend/recvラッパー関数をプリロードすることで機能します。
私が見つけた最大の欠点は、有限の帯域幅を共有したい複数のアプリケーションを調整するのが難しいことでした。「だまされた」は役に立ちますが、私はそれが複雑だと感じました。
2017年の更新:トリクルがhttps://github.com/mariusae/trickleに移動したようです