2017-10-31 18 views
6

Delphi XE 6 및 Indy10을 사용하여 FTP 서버를 개발 중입니다. 문제는 다운로드 속도를 제한해야한다는 것입니다 (예 : 1KB/s, 1MB/s 등 구성 가능해야 함). 작동하지 않습니다. 나는 BitsPerSec 등과 같은 소품을 알고 있지만 이것은 RETR 명령을 사용한 파일 교환이 아닌 프로토콜 데이터 교환에만 영향을 미친다. IdFTPServer.pass에서 볼 수 있고 스트림은 문자열로 변환되고 반복/반복 루프 (IOHandler.Write() 사용)와 함께 보내지 만 업로드/다운로드 프로세스의 제어 형식이 필요하고 속도를 제한 할 수 있어야합니다. 모든 들어오는 클라이언트 연결. 이걸 이루기 위해 어떤 도움이 필요합니까?.IndyFtpServer (v10)로 검색 한 파일의 속도를 제한하는 방법

PD : 불쌍한 영어에 대한 죄송합니다.

는이 코드로 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

답변

11

문제는 내가 (구성 예해야합니다. 등 1킬로바이트/s의 1 메가 바이트/s의) 다운로드의 속도를 제한 할 필요가 있다는 것입니다 그리고 난 그것이 작동하지 않습니다 . 나는 BitsPerSec, 등등 같은 일부 소품을 알고 있지만 이것은 프로토콜 데이터 교환에만 영향을 미치지, RETR 명령을 사용한 파일 교환에는 영향을 미치지 않습니다.

BitsPerSec은 (RecvBitsPerSecSendBitsPerSec 및 특성과 함께) TIdInterceptThrottler 클래스의 속성이다. 해당 클래스의 인스턴스는 Intercept 속성을 통해 TIdTCPConnection 개체에 할당 될 수 있습니다. 이것은 명령 연결에만 국한되지 않고 전송 연결에도 사용할 수 있습니다.

당신은 같은 OnRetrieveFile 경우에서와 같이, TIdFTPServerContext.DataChannel.FDataChannel 부재를 통하여 TIdFTPServer에서 파일 전송의 TIdTCPConnection 개체에 액세스 할 수 있습니다

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; 

대안은 가상 Read()를 오버라이드 (override)하는 자신의 T(File)Stream 파생 클래스를 만드는 것입니다 및 Write() 메서드를 사용하여 필요에 따라 사용자 자신의 제한을 수행 한 다음 해당 클래스의 인스턴스를 OnRetrieveFileOnStoreFile 이벤트의 VStream 매개 변수에 할당합니다.

내가 IdFTPServer.pas에서보고, 스트림을 문자열로 변환 및 루프까지/반복으로 전송 (IOHandler.Write와())

아니, 스트림을 문자열로 변환되지 않습니다 . 코드를 잘못 읽었습니다. 스트림의 내용은 IOHandler.Write(TStream) 메서드에 대한 단일 호출에서 그대로 이진 데이터로 전송됩니다.

하지만 업로드/다운로드 프로세스의 제어 형식이 필요하며 모든 수신 클라이언트 연결의 속도를 제한 할 수 있어야합니다.

위 참조.

은 내가 RETR 명령

당신은 RETR 명령 직접을 취급하지 말아위한 CommandHandler을 구현하려고합니다. TIdFTPServer가 이미 해당 작업을 수행합니다. 다운로드를 준비하기 위해 OnRetrieveFile 이벤트를 사용하고 업로드를 위해 OnStoreFile 이벤트를 사용해야합니다.

+1

당신은 최고의 형제입니다. 나는 코드를 읽는 데 몇 가지 실수를하지만, 이것이 내가 필요한 것이다. 나는 오전 5시에 일하기 때문에 나쁜 조건에서 눈과 두뇌를 권합니다. 나는 당신과 함께 멋진 수업 BufferedFileStream (일부 calc 및 일부 sleep)과 함께 스로틀을 수행합니다. 그러나 지금 나는 이것을보고 완벽한 방법입니다. 다시 한번 고마워! 이 담당자와 나는 아직 투표를 할 수 없습니다. – WoNDeR