代码之家  ›  专栏  ›  技术社区  ›  Wo_0NDeR ᵀᴹ

如何使用IndyFtpServer(v10)限制检索文件的速度

  •  6
  • Wo_0NDeR ᵀᴹ  · 技术社区  · 7 年前

    我正在用Delphi XE 6和Indy10开发一个FTP服务器。问题是我需要限制下载速度(必须是可配置的,例如1 KB/s、1 MB/s等),但我无法使其工作。我知道一些道具,如BitsPerSec等。但这只影响协议数据交换,而不影响使用RETR命令的文件交换。我在IdFTPServer中看到了。通过,流被转换为字符串,并使用repeat/until循环发送(使用IOHandler.Write()),但我需要某种形式的控制上载/下载过程,并能够限制所有传入客户端连接的速度。请给我一些帮助?。

    对不起,我的英语很差。

    我尝试用以下代码实现RETR命令的CommandHandler:

    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;
    

    但是Filezilla FTP客户端像其他命令的一部分一样显示流数据。

    Filezilla Client

    1 回复  |  直到 7 年前
        1
  •  12
  •   Remy Lebeau    7 年前

    问题是我需要限制下载速度(必须是可配置的,例如1 KB/s、1 MB/s等),但我无法使其工作。我知道一些道具,比如 BitsPerSec 等等,但这只影响协议数据交换,而不影响与的文件交换 RETR 命令

    比特斯佩尔塞克 是的属性 TIdInterceptThrottler 类(以及 RecvBitsPerSec SendBitsPerSec TIdTCPConnection 通过its的对象 Intercept 所有物这不仅限于命令连接,还可以用于传输连接。

    您可以访问 TIDTCP连接 文件传入的对象 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 参数 OnStoreFile 事件。

    我明白了 IdFTPServer.pas ,流被转换为字符串,并使用repeat/until循环发送(使用IOHandler.Write())

    不,流不会转换为字符串。你误读了代码。流的内容在对 IOHandler.Write(TStream) 方法

    但我需要某种形式的控制上传/下载过程,并能够限制所有传入客户端连接的速度。

    见上文。

    你不应该处理 命令 . TIdFTPServer 已经为你做了。你应该使用 事件来准备下载

    推荐文章