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

发布于 2024-07-25 08:08:38 字数 169 浏览 4 评论 0原文

我正在编写一个实用程序,它将上传一堆文件,并希望提供限制上传速率的选项。 使用 TcpClient 类时限制上传速率的最佳方法是什么? 我的第一直觉是一次使用有限数量的字节调用 NetworkStream.Write(),在调用之间休眠(如果流尚未完成写入,则跳过调用),直到上传缓冲区。 以前有人实施过类似的事情吗?

I'm writing a utility that will be uploading a bunch of files, and would like to provide the option to rate limit uploads. What is the best approach for rate limiting uploads when using the TcpClient class? My first instinct is to call NetworkStream.Write() with a limited number of bytes at a time, sleeping between calls (and skipping a call if the stream isn't done writing yet) until the buffer is uploaded. Has anyone implemented something like this before?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦情居士 2024-08-01 08:08:39

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

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

这是未经测试的代码草案,但我认为这足以了解主要思想。

Implementing speed limit is relatively easy, take a look at the following snippet:

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

This is draft untested code, but I think it is enough to get the main idea.

佞臣 2024-08-01 08:08:39

您可能还想考虑 BITS(后台互联网传输服务),而不是创建它,它允许用户(或管理员)配置带宽,并处理传输排队。

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

Rather than creating this, you might also want to consider BITS (Background Internet Transfer Service) which allows the user (or admin) to configure bandwidth, and will handle queuing of transfers.

It does require specific support on the server (including in IIS, but needs enabling).

兮子 2024-08-01 08:08:39

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

如果我们使用“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()

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

I know this is an old entry, but i think this information can be usefull for someone who get here through google or another web search.

If we use the solution posted by "arbiter" we will found that the thread will send a large amount of data, and then it will sleep for a large amount of time, cause the usually speed limits are over 32 to 200 kb per second while with an standar pc, the thread can manage over 10 to 100 MB per second.

I used the next solution into my project. Note that is only a piece of code and you will have to modify it to adjust to your own. It is write in Visual basic. By the way, sorry about my english...

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

Hope this can help anyone.
Bye.

笑脸一如从前 2024-08-01 08:08:39

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

I did some research on the TcpClient class and this is how I accomplished it:

           '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

I'm sure you know how to convert it to c# if you decide to use it yourself though and maybe it's just my code, but it seems clearer than the other answers.

This is in the main loop, and bandwidthTimer is a Date object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文