Как я могу оценить ограничение загрузки с помощью TcpClient? - PullRequest
3 голосов
/ 30 июня 2009

Я пишу утилиту, которая будет загружать кучу файлов, и хотела бы предоставить возможность ограничить загрузку. Каков наилучший подход к загрузке с ограничением скорости при использовании класса TcpClient? Мой первый инстинкт - это вызывать NetworkStream.Write () с ограниченным количеством байтов за раз, спать между вызовами (и пропускать вызов, если поток еще не закончил запись), пока буфер не будет загружен. Кто-нибудь реализовывал что-то подобное раньше?

Ответы [ 4 ]

6 голосов
/ 01 июля 2009

Реализация ограничения скорости относительно проста, взгляните на следующий фрагмент:

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

Это черновик непроверенного кода, но я думаю, что этого достаточно, чтобы понять основную идею.

1 голос
/ 22 декабря 2011

Я провел некоторое исследование класса 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.

1 голос
/ 03 сентября 2010

Я знаю, что это старая запись, но я думаю, что эта информация может быть полезна для тех, кто попадает сюда через Google или другой веб-поиск.

Если мы используем решение, опубликованное «арбитром», мы обнаружим, что поток будет отправлять большой объем данных, а затем он будет находиться в спящем режиме в течение большого количества времени, поскольку обычно ограничения скорости превышают 32–200 кб. в секунду при использовании стандартного ПК поток может обрабатывать от 10 до 100 МБ в секунду.

Я использовал следующее решение в своем проекте. Обратите внимание, что это всего лишь кусок кода, и вам придется изменить его, чтобы настроить его по своему усмотрению. Это написать в 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()

Надеюсь, это может кому-нибудь помочь. Bye.

1 голос
/ 30 июня 2009

Вместо того, чтобы создавать это, вы также можете рассмотреть BITS (Фоновая служба Интернет-передачи), которая позволяет пользователю (или администратору) настраивать пропускную способность и обрабатывает очереди передачи.

Требуется специальная поддержка на сервере (в том числе в IIS, но требуется включение).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...