如何使用 IndyFtpServer (v10) 限制检索文件的速度
How to limit speed of retrieved files with IndyFtpServer (v10)
我正在使用 Delphi XE 6 和 Indy10 开发 FTP 服务器。问题是我需要限制下载速度(必须是可配置的,例如 1 KB/s、1 MB/s 等),但我没有让它工作。我知道一些道具,如 BitsPerSec 等,但这只会影响协议数据交换,而不影响与 RETR 命令的文件交换。我在 IdFTPServer.pass 中看到,流被转换为字符串并使用 repeat/until 循环发送(使用 IOHandler.Write()),但我需要某种形式的控制 upload/download 过程并能够限制所有传入客户端连接的速度。请帮忙实现这个目标?
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
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 with RETR
command.
BitsPerSec
是 TIdInterceptThrottler
class 的 属性(以及 RecvBitsPerSec
和 SendBitsPerSec
属性)。 class 的实例可以通过其 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
派生 class 来覆盖虚拟 Read()
和 Write()
方法以根据需要执行您自己的节流,然后分配class 到 OnRetrieveFile
和 OnStoreFile
事件的 VStream
参数的实例。
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
事件来准备上传。
我正在使用 Delphi XE 6 和 Indy10 开发 FTP 服务器。问题是我需要限制下载速度(必须是可配置的,例如 1 KB/s、1 MB/s 等),但我没有让它工作。我知道一些道具,如 BitsPerSec 等,但这只会影响协议数据交换,而不影响与 RETR 命令的文件交换。我在 IdFTPServer.pass 中看到,流被转换为字符串并使用 repeat/until 循环发送(使用 IOHandler.Write()),但我需要某种形式的控制 upload/download 过程并能够限制所有传入客户端连接的速度。请帮忙实现这个目标?
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
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
class 的 属性(以及 RecvBitsPerSec
和 SendBitsPerSec
属性)。 class 的实例可以通过其 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
派生 class 来覆盖虚拟 Read()
和 Write()
方法以根据需要执行您自己的节流,然后分配class 到 OnRetrieveFile
和 OnStoreFile
事件的 VStream
参数的实例。
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
事件来准备上传。