2017-10-31 6 views
6

Ich entwickle einen FTP-Server mit Delphi XE 6 und Indy10. Das Problem ist, dass ich die Geschwindigkeit des Downloads begrenzen muss (muss zB 1 KB/s, 1 MB/s, etc. konfigurierbar sein) und ich mache es nicht funktioniert. Ich kenne einige Requisiten wie BitsPerSec, etc., aber dies betrifft nur den Protokolldatenaustausch, nicht den Datenaustausch mit dem RETR-Befehl. Ich sehe in IdFTPServer.pass, und der Stream wird in Zeichenfolge konvertiert und mit einer Wiederholungsschleife (mit IOHandler.Write()) senden, aber ich brauche eine Form der Kontrolle der Upload/Download-Prozess und in der Lage, die Geschwindigkeit zu begrenzen alle eingehenden Clientverbindungen. Einige helfen dies bitte zu erreichen.Wie Geschwindigkeit der abgerufenen Dateien mit IndyFtpServer (v10) zu begrenzen

PD: Sorry für mein schlechtes Englisch.

ich versuche, ein Command für den RETR-Befehl mit diesem Code zu implementieren:

procedure TForm1.IdFTPServer1CommandHandlers0Command(ASender: TIdCommand); 
var 
    LContext : TIdFTPServerContext; 
    vStream: TFileStream; 
    path: String; 
    vX: Integer; 
    LEncoding: IIdTextEncoding; 
begin 

    LEncoding := IndyTextEncoding_8Bit; 
    LContext := ASender.Context as TIdFTPServerContext; 
    path := 'D:\indy_in_depth.pdf'; 


    try 
    vStream := TFileStream.Create(path, fmOpenRead); 
    //LContext.DataChannel.FtpOperation := ftpRetr; 
    //LContext.DataChannel.Data := VStream; 
    LContext.DataChannel.OKReply.SetReply(226, RSFTPDataConnClosed); 
    LContext.DataChannel.ErrorReply.SetReply(426, RSFTPDataConnClosedAbnormally); 

    ASender.Reply.SetReply(150, RSFTPDataConnToOpen); 
    ASender.SendReply; 

    Memo1.Lines.Add('Sending a file with: ' + IntToStr(vStream.Size) + ' bytes'); 
    //Make control of speed here ! 
    for vX := 1 to vStream.Size do 
     begin 
     vStream.Position := vX; 
     LContext.Connection.IOHandler.Write(vStream, 1, False); 
     if vX mod 10000 = 0 then 
      Memo1.Lines.Add('Sended byte: ' + IntToStr(vX)); 
     end; 

    //LContext.DataChannel.InitOperation(False); 

    //LContext.Connection.IOHandler.Write(vStream); 

    //LContext.KillDataChannel; 
    LContext.Connection.Socket.Close; 

    VStream.Free; 
    except 
    on E: Exception do 
    begin 
     ASender.Reply.SetReply(550, E.Message); 
    end; 
    end; 

end; 

Aber die Filezilla FTP-Client Show-Stream-Daten wie ein Teil von anderem Befehl.

Filezilla Client

Antwort

11

Das Problem ist, dass ich brauche, um die Geschwindigkeit des Downloads zu begrenzen (muss konfigurierbar Ex sein. 1 KB/s, 1 MB/s, etc.) und ich es nicht funktioniert . Ich kenne einige Requisiten wie BitsPerSec usw., aber dies betrifft nur den Protokolldatenaustausch, nicht den Datenaustausch mit RETR Befehl.

BitsPerSec ist eine Eigenschaft der TIdInterceptThrottler Klasse (zusammen mit RecvBitsPerSec und SendBitsPerSec Eigenschaften). Eine Instanz dieser Klasse kann über ihre Eigenschaft Intercept einem beliebigen Objekt TIdTCPConnection zugewiesen werden. Dies ist nicht nur auf die Befehlsverbindung beschränkt, sondern kann auch für Übertragungsverbindungen verwendet werden.

Sie können auf das TIdTCPConnection Objekt einer Dateiübertragung in TIdFTPServer über das TIdFTPServerContext.DataChannel.FDataChannel Mitglied, wie in der OnRetrieveFile Veranstaltung:

type 
    // the TIdDataChannel.FDataChannel member is 'protected', 
    // so use an accessor class to reach it... 
    TIdDataChannelAccess = class(TIdDataChannel) 
    end; 

procedure TForm1.IdFTPServer1RetrieveFile(ASender: TIdFTPServerContext; 
    const AFileName: TIdFTPFileName; var VStream: TStream); 
var 
    Conn: TIdTCPConnection; 
begin 
    Conn := TIdDataChannelAccess(ASender.DataChannel).FDataChannel; 
    if Conn.Intercept = nil then 
    Conn.Intercept := TIdInterceptThrottler.Create(Conn); 
    TIdInterceptThrottler(Conn.Intercept).BitsPerSec := ...; 
    VStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite); 
end; 

Eine Alternative ist, Ihre eigene T(File)Stream abgeleitete Klasse erstellen, um die virtuellen Read() außer Kraft zu setzen und Write() Methoden, um bei Bedarf eine eigene Drosselung durchzuführen, und weisen Sie anschließend dem VStream-Parameter der Ereignisse OnRetrieveFile und OnStoreFile eine Instanz dieser Klasse zu.

ich in IdFTPServer.pas zu sehen, und der Strom wird in einem String umgewandelt und mit einer Wiederholung/bis Schleife senden (mit IOHandler.Write())

Nein, ein Strom wird nicht in einen String umgewandelt . Sie lesen den Code falsch. Der Inhalt eines Streams wird unverändert als Binärdaten in einem einzigen Aufruf an die Methode IOHandler.Write(TStream) gesendet.

aber ich brauche eine Form der Kontrolle der Upload/Download-Prozess und in der Lage sein, die Geschwindigkeit für alle eingehenden Client-Verbindungen zu begrenzen.

Siehe oben.

ich versuche, ein Command für den RETR Befehl zu implementieren

Sie sollten nicht direkt den RETR Befehl werden handhaben. TIdFTPServer macht das schon für Sie. Sie sollten stattdessen das Ereignis OnRetrieveFile verwenden, um Downloads vorzubereiten, und das Ereignis OnStoreFile für Uploads.

+1

Sie sind der beste Bruder. Ich mache einige Fehler beim Lesen des Codes, aber genau das brauche ich. Ich arbeite 5 Uhr morgens, also Augen und Gehirn in schlechten Bedingungen lol. Ich mache etwas Throttle mit dir super Klasse BufferedFileStream (mit etwas calc und einigen Betten). Aber jetzt sehe ich das und ist der perfekte Weg. Nochmals vielen Dank !. Mit diesem Rep kann ich noch nicht Ups machen. – WoNDeR

Verwandte Themen