2009-06-30 15 views
3

私は、たくさんのファイルをアップロードするユーティリティを書いています。レート制限のアップロードにオプションを提供したいと考えています。 TcpClientクラスを使用しているときにレート制限のアップロードに最適な方法は何ですか?私の最初の本能は、一度に限られた数のバイトでNetworkStream.Write()を呼び出すことです。バッファがアップロードされるまで、コール間でスリープします(ストリームがまだ書き込まれていない場合は呼び出しをスキップします)。誰もこれの前にこのような何かを実装しましたか?TcpClientを使用してアップロードを制限するにはどうすればよいですか?

答えて

1

これを作成するのではなく、ユーザー(または管理者)が帯域幅を設定できるBITS(バックグラウンドインターネット転送サービス)を検討し、転送のキューイングを処理することも考えられます。

サーバーでの特定のサポートが必要です(IISを含むが、有効にする必要があります)。制限速度を実装

+0

残念ながら私のサーバーはLAMPスタック上にあり、BITSは動作しません。しかし、よく知っている。 – Luke

6

が比較的容易であり、次のスニペットを見てみましょう:

const int OneSecond = 1000; 

int SpeedLimit = 1024; // Speed limit 1kib/s 

int Transmitted = 0; 
Stopwatch Watch = new Stopwatch(); 
Watch.Start(); 
while(...) 
{ 
    // Your send logic, which return BytesTransmitted 
    Transmitted += BytesTransmitted; 

    // Check moment speed every five second, you can choose any value 
    int Elapsed = (int)Watch.ElapsedMilliseconds; 
    if (Elapsed > 5000) 
    { 
     int ExpectedTransmit = SpeedLimit * Elapsed/OneSecond; 
     int TransmitDelta = Transmitted - ExpectedTransmit; 
     // Speed limit exceeded, put thread into sleep 
     if (TransmitDelta > 0) 
      Thread.Wait(TransmitDelta * OneSecond/SpeedLimit); 

     Transmitted = 0; 
     Watch.Reset(); 
    } 
} 
Watch.Stop(); 

これはドラフト未テストコードですが、私はメインのアイデアを取得するのに十分だと思います。

+0

私はあなたがwatch.restartを望むと思うので、経過時間を0にリセットしてから、タイマーを再起動します。 watch.resetは時刻を0に戻し、itmerを停止します。 – zeocrash

1

私はこれが古いエントリだと知っていますが、私はこの情報は、Googleや別のWeb検索を介してここにいる人にとって有益だと思います。

「アービター」によって投稿されたソリューションを使用すると、スレッドが大量のデータを送信し、通常は速度制限が32〜200を超えるため、大量の時間スリープ状態になることがわかりますkb /秒、スタンドアロンのPCの場合、スレッドは10〜100MB /秒を管理できます。

私は自分のプロジェクトに次のソリューションを使用しました。コードは単なるコードであり、独自のコードに変更する必要があります。これはVisual Basicで書かれています。ちなみに、私の英語については申し訳ありません。

Dim SpeedLimit As Long = User.DownloadKbSpeedLimit * 1024, Elapsed As Long = 0 
    'Try to adjust buffersize to the operating system. 
    'Seem to be stupid, but the test shows it goes better this way. 
    If Environment.Is64BitOperatingSystem Then 
     stream.BufferSize = 64 * 1024 
    Else 
     stream.BufferSize = 32 * 1024 
    End If 
    'If buffersize is bigger than speedlimite, cut the buffersize to avoid send too much data 
    If SpeedLimit > 0 AndAlso e.BufferSize > SpeedLimit Then e.BufferSize = SpeedLimit 
    'Create Byte array to send data 
    Dim Buffer(e.BufferSize) As Byte 
    'Create Watch to control the speed 
    Dim Transmitted As Integer = 0, Watch As New Stopwatch() 
    Watch.Start() 
    'Start sending data 
    While True 
     'This enables the program to control another events or threads 
     System.Threading.Thread.Sleep(10) 
     Windows.Forms.Application.DoEvents() 
     'Recover data and write into the stream 
     If SpeedLimit = 0 OrElse Transmitted < SpeedLimit Then 
      Dim Readed As Integer = SomeFileStream.Read(Buffer, 0, Buffer.Length) 
      If Readed 0 Then Exit While 
      Stream.Write(Buffer, Readed) 
      Transmitted += Readed 
     End If 
     If Watch.ElapsedMilliseconds > OneSecond Then 
      Transmitted = 0 
      Watch.Restart() 
     End If 
    End While 
    Watch.Stop() 
    Stream.Close() : Stream.Dispose() 

これは誰にも役立つことを願っています。 さようなら。

+0

入力していただきありがとうございます。その古いトピックであっても、アクティビティによって気づかれるようになります:) – Luke

1

私がれるtcpClientクラス上のいくつかの研究を行なったし、これは私がそれを達成する方法である:

  'Throttle network Mbps... 
      bandwidthUsedThisSecond = session.bytesSentThisSecond + session.bytesRecievedThisSecond 
      If bandwidthTimer.AddMilliseconds(50) > Now And bandwidthUsedThisSecond >= (Mbps/20) Then 
       While bandwidthTimer.AddMilliseconds(50) > Now 
        Thread.Sleep(1) 
       End While 
      End If 
      If bandwidthTimer.AddMilliseconds(50) <= Now Then 
       bandwidthTimer = Now 
       session.bytesRecievedThisSecond = 0 
       session.bytesSentThisSecond = 0 
       bandwidthUsedThisSecond = 0 
      End If 

私はあなたがあなたががそれを自分で使用することにした場合のC#に変換する方法を知っていると確信しているし、多分それはですちょうど私のコードが、他の答えよりもはっきりしているようです。

これはメインループにあり、bandwidthTimerはDateオブジェクトです。

関連する問題