2009-06-30 24 views
3

我正在編寫一個實用程序,它將上傳一堆文件,並希望提供限制上傳速度的選項。使用TcpClient類時,限速上傳的最佳方法是什麼?我的第一個直覺是一次調用NetworkStream.Write(),限制數量的字節,在兩次調用之間進行睡眠(並且在流尚未完成時跳過一個調用)直到緩衝區被上傳。有沒有人實施過這樣的事情?我如何評價使用TcpClient進行上傳?

回答

1

您可能還想考慮允許用戶(或管理員)配置帶寬並處理傳輸排隊的BITS(後臺Internet傳輸服務),而不是創建它。

它確實需要特定的服務器支持(包括在IIS中,但需要啓用)。

+0

嗯,不幸的是我的服務器在LAMP堆棧上,所以BITS不起作用。不過很高興知道。 – Luke 2009-06-30 14:13:17

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 2015-09-30 10:08:50

1

我知道這是一箇舊的條目,但我認爲這個信息可以用於通過谷歌或其他網絡搜索到達這裏的人有用。

如果我們使用「arbiter」發佈的解決方案,我們會發現線程會發送大量的數據,然後它會睡眠大量的時間,導致通常的速度限制超過32到200 kb每秒,而與標準PC,線程可以管理超過10到100 MB每秒。

我在我的項目中使用了下一個解決方案。請注意,這只是一段代碼,您必須對其進行修改才能適應您自己的需求。它是用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 2010-09-03 00:27:41

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對象。