2009-06-30 5 views
3

Ich schreibe ein Dienstprogramm, das eine Reihe von Dateien hochladen wird, und möchte die Möglichkeit bieten, Limit-Uploads zu bewerten. Was ist der beste Ansatz für die Rate-limiting-Uploads bei Verwendung der TcpClient-Klasse? Mein erster Instinkt besteht darin, NetworkStream.Write() mit einer begrenzten Anzahl von Bytes gleichzeitig aufzurufen, zwischen den Aufrufen zu schlafen (und einen Anruf zu überspringen, wenn der Stream noch nicht fertig geschrieben ist), bis der Puffer hochgeladen ist. Hat jemand so etwas schon mal umgesetzt?Wie kann ich einen Upload mit TcpClient einschränken?

Antwort

1

Anstatt dies zu erstellen, sollten Sie auch BITS (Background Internet Transfer Service) in Betracht ziehen, mit dem der Benutzer (oder Administrator) die Bandbreite konfigurieren und Warteschlangen von Übertragungen verarbeiten kann.

Es erfordert spezielle Unterstützung auf dem Server (einschließlich in IIS, muss aber aktiviert werden).

+0

Hmm, leider ist mein Server auf dem LAMP-Stack, damit BITS nicht funktioniert. Gut zu wissen aber. – Luke

6

Geschwindigkeitsbegrenzung Implementierung ist relativ einfach, werfen Sie einen Blick auf die folgenden Ausschnitt:

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

Dieser Entwurf ungetesteten Code ist, aber ich denke, es ist genug, um die Hauptidee zu bekommen.

+0

Ich denke, dass Sie eine watch.restart dort als die abgelaufene Zeit zurück auf 0 zurückgesetzt und dann den Timer neu starten möchten. watch.reset setzt die Zeit einfach auf 0 zurück und stoppt den itmer – zeocrash

1

Ich weiß, dass dies ein alter Eintrag ist, aber ich denke, dass diese Informationen für jemanden nützlich sein können, der durch Google oder eine andere Websuche hierher kommt.

Wenn wir die Lösung verwenden, die von "arbiter" gepostet wird, werden wir feststellen, dass der Thread eine große Menge an Daten senden wird und dann für eine lange Zeit schlafen wird, da die Geschwindigkeitsbegrenzungen normalerweise zwischen 32 und 200 liegen Bei einem Standard-PC kann der Thread über 10 bis 100 MB pro Sekunde verwalten.

Ich habe die nächste Lösung in meinem Projekt verwendet. Beachten Sie, dass es sich nur um ein Stück Code handelt, und Sie müssen es ändern, um es an Ihre eigenen anzupassen. Es ist in Visual Basic schreiben. Übrigens, sorry über mein Englisch ...

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

Hoffe, dass dies jedem helfen kann. Tschüss.

+0

Danke für die Eingabe. Obwohl es ein altes Thema ist, wird die Aktivität dafür sorgen, dass es bemerkt wird :) – Luke

1

Ich habe einige Nachforschungen über die TcpClient Klasse und das ist, wie ich es erreicht:

  '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 

Ich bin sicher, Sie wissen, wie es zu C# zu konvertieren, wenn Sie es sich allerdings zu bedienen und es ist vielleicht nur mein Code, aber es scheint klarer als die anderen Antworten.

Dies ist in der Hauptschleife, und bandwidthTimer ist ein Date-Objekt.

Verwandte Themen