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客户端显示流数据,就像其他命令的一部分.
解决方法
The problem is that i need to limit the speed of download (must be configurable Ex. 1 KB/s,1 MB/s,etc.) and i don’t make it work. I know some props like
BitsPerSec
,etc. but this only affect the protocol data exchange,not the file exchange withRETR
command.
BitsPerSec是TIdInterceptThrottler类的属性(以及RecvBitsPerSec和SendBitsPerSec属性).可以通过其Intercept属性将该类的实例分配给任何TIdTCPConnection对象.这不仅限于命令连接,它也可以用于传输连接.
您可以通过TIdFTPServerContext.DataChannel.FDataChannel成员访问TIdFTPServer中文件传输的TIdTCPConnection对象,例如在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()方法,根据需要执行自己的限制,然后将该类的实例分配给OnRetrieveFile的VStream参数,OnStoreFile事件.
I see in
IdFTPServer.pas
,and the Stream is converted to string and send with a repeat/until loop (with IOHandler.Write())
不,流不会转换为字符串.你误读了代码.在对IOHandler.Write(TStream)方法的单个调用中,流的内容将作为二进制数据原样发送.
but i need some form of control the upload/download process and be able to limit the speed for all incoming client connections.
往上看.
I try to implement a CommandHandler for the RETR command
您不应该直接处理RETR命令. TIdFTPServer已经为您做到了这一点.您打算使用OnRetrieveFile事件来准备下载,并使用OnStoreFile事件进行上载.