如何使用TcpClient对上传进行速率限制?

我正在编写一个将上传大量文件的实用程序,并希望提供限速上传的选项。 使用TcpClient类时,限速上传的最佳方法是什么? 我的第一个本能是一次调用具有有限字节数的NetworkStream.Write(),在调用之间hibernate(如果尚未写入流,则跳过调用),直到缓冲区被上传。 有没有人之前实现过这样的东西?

实现速度限制相对容易,请看下面的代码片段:

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(); 

这是未经测试的草案代码,但我认为这足以获得主要想法。

您可能还需要考虑允许用户(或管理员)配置带宽并将处理传输排队的BITS(后台Internet传输服务),而不是创建此项。

它确实需要服务器上的特定支持(包括在IIS中,但需要启用)。

我知道这是一个旧条目,但我认为这些信息对于通过谷歌或其他网络搜索到达此处的人来说非常有用。

如果我们使用“仲裁器”发布的解决方案,我们会发现线程会发送大量数据,然后它会睡眠很长时间,因为通常速度限制超过每秒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() 

希望这可以帮助任何人。 再见。

我对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对象。