How to limit the speed of receiving files using IndyFtpServer (v10)

I am developing an FTP server with Delphi XE 6 and Indy10. The problem is that I need to limit the download speed (the example should be configured at 1 KB / s, 1 MB / s, etc.), and I do not make it work. I know some details, such as BitsPerSec, etc., But this only affects the exchange of protocol data, and not the exchange of files with the RETR command. I see in IdFTPServer.pass, and Stream is converted to a string and sends with a repeat / until loop (with IOHandler.Write ()), but I need a certain form of control for the upload / download process and the ability to limit the speed for all incoming client connections. Some help to achieve this, please?

PD: Sorry for my bad English.

I am trying to implement CommandHandler for a RETR command with this code:

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;

But the Filezilla FTP client shows streaming data as part of another command.

Filezilla client

+6
source share
1 answer

The problem is that I need to limit the download speed (the example should be configured at 1 KB / s, 1 MB / s, etc.), and I do not make it work. I know some type details BitsPerSec, etc., But this only affects the exchange of protocol data, and not the exchange of files with the team RETR.

BitsPerSec TIdInterceptThrottler ( RecvBitsPerSec SendBitsPerSec). TIdTCPConnection Intercept. , .

TIdTCPConnection TIdFTPServer TIdFTPServerContext.DataChannel.FDataChannel, , OnRetrieveFile:

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;

T(File)Stream Read() Write() , VStream OnRetrieveFile OnStoreFile.

IdFTPServer.pas, Stream repeat/until ( IOHandler.Write())

, . . - IOHandler.Write(TStream).

/ .

. .

CommandHandler RETR

RETR. TIdFTPServer . OnRetrieveFile OnStoreFile .

+11

All Articles