Indy IdFTP 在活动连接上失败
Indy IdFTP fails on Active connection
我正在尝试使用 Indy 的 IDFTP 通过 FTP 发送和接收一些文件。
function TDatosFTP.TransfiereFTP(Fm: TForm): boolean;
var
TimeoutFTP: integer;
begin
Result := false;
with TIdFTP.Create(Fm) do
try
try
TimeoutFTP := 2000;
Host := Servidor;
Port := 21;
UserName := Usuario;
PassWord := Contra;
Passive := Pasivo;
Connect(true, TimeoutFTP);
if not Connected then
begin
Error := true;
end
else
begin
TransferType := ftASCII;
if Binario then
TransferType := ftBinary;
OnWorkEnd := FinDeTransmision;
if Descargar then
Get(Remoto , Local, True)
else
Put(InterpretarRutaEspecial(Local), Remoto, True);
if Descargar and Borrar then
Delete(Remoto);
Disconnect;
Result := true;
Fm.Hide;
end;
Except on E: Exception do
Mensaje := E.Message;
end;
finally
Free;
end;
if not Result then
ErrorTransmision;
end;
每当我尝试在主动模式下执行 PUT/GET 时,我都会收到以下错误:EIdProtocolReplyError:“无法建立连接”。它在被动模式下工作正常。
问题是我想使用 Indy(在项目的其他地方使用)但是以前版本的代码,使用 OverbyteIcsFtpCli 在主动和被动模式下工作正常 both。
这是使用 OverbyteIcsFtpCli 的代码:
function TDatosFTP.TransfiereFTP(Fm: TForm): boolean;
begin
with TFtpClient.Create(Fm) do
try
HostName := Servidor;
Port := '21';
UserName := Usuario;
PassWord := Contra;
HostDirName := '';
HostFileName := Origen;
LocalFileName := InterpretarRutaEspecial(Destino);
Binary := Binario;
Passive := Pasivo;
OnRequestDone := FinDeTransmision;
if Descargar then
Result := Receive
else
Result := Transmit;
OnRequestDone := nil;
if Descargar and Borrar then
Delete;
Result := Result and not Error;
Fm.Hide;
if not Result then
ErrorTransmision;
finally
Free;
end;
end;
所以我使用 wireshark 查看了引擎盖,我发现 Indy 的 FTP 没有回复来自服务器的一些消息。
这是与 OverBytes 的文件传输握手 FTP:
我用黄色突出显示了服务器和客户端之间发送的两个开始数据传输的数据包。
现在让我们看看 Indy 的 FTP:
会发生什么
服务器正在发送数据包以开始文件传输,但 IdFTP 没有应答。
我见过 but this two tests where ran in the same computer, same network connection, same firewall, etc. Also this one,但我希望 FTP 在主动和被动模式下都能工作 。
发生了什么事?
在 Active 模式传输中,FTP 服务器创建到接收方的传出 TCP 连接。
您的 Wireshark 捕获清楚地表明,有问题的 FTP 服务器正在创建传输连接 BEFORE 发送对 RETR
命令的响应,让您的客户端知道连接正在进行。 TFtpClient
在收到 RETR
响应之前接受该连接。但是 TIdFTP
在接受传输连接之前等待 RETR
响应(这也适用于 TIdFTP
对 STOR
/STOU
/[ 的处理=19=] 命令。
LPortSv.BeginListen; // <-- opens a listening port for transfer
...
SendPort(LPortSv.Binding); // <-- sends the PORT command
...
SendCmd(ACommand, [125, 150, 154]); // <-- sends the RETR command and waits for a response!
...
LPortSv.Listen(ListenTimeout); // <-- accepts the transfer connection
...
重读RFC 959,内容如下:
The passive data transfer process (this may be a user-DTP or a second server-DTP) shall "listen" on the data port prior to sending a transfer request command. The FTP request command determines the direction of the data transfer. The server, upon receiving the transfer request, will initiate the data connection to the port. When the connection is established, the data transfer begins between DTP's, and the server-PI sends a confirming reply to the user-PI.
ICS 是异步的,所以这种情况它处理起来不是什么大问题。但是 Indy 使用阻塞套接字,所以 TIdFTP
需要更新以解决这种情况,可能通过同时监视命令和传输端口,这样它就可以采取相应的行动,而不管传输连接和命令响应的顺序如何到达。
我为此在 Indy 的问题跟踪器中开了一张票:
#300: TIdFTP fails on Active mode transfer connection with vsFTPd
更新: the fix 现在已合并到主代码中。
我正在尝试使用 Indy 的 IDFTP 通过 FTP 发送和接收一些文件。
function TDatosFTP.TransfiereFTP(Fm: TForm): boolean;
var
TimeoutFTP: integer;
begin
Result := false;
with TIdFTP.Create(Fm) do
try
try
TimeoutFTP := 2000;
Host := Servidor;
Port := 21;
UserName := Usuario;
PassWord := Contra;
Passive := Pasivo;
Connect(true, TimeoutFTP);
if not Connected then
begin
Error := true;
end
else
begin
TransferType := ftASCII;
if Binario then
TransferType := ftBinary;
OnWorkEnd := FinDeTransmision;
if Descargar then
Get(Remoto , Local, True)
else
Put(InterpretarRutaEspecial(Local), Remoto, True);
if Descargar and Borrar then
Delete(Remoto);
Disconnect;
Result := true;
Fm.Hide;
end;
Except on E: Exception do
Mensaje := E.Message;
end;
finally
Free;
end;
if not Result then
ErrorTransmision;
end;
每当我尝试在主动模式下执行 PUT/GET 时,我都会收到以下错误:EIdProtocolReplyError:“无法建立连接”。它在被动模式下工作正常。
问题是我想使用 Indy(在项目的其他地方使用)但是以前版本的代码,使用 OverbyteIcsFtpCli 在主动和被动模式下工作正常 both。
这是使用 OverbyteIcsFtpCli 的代码:
function TDatosFTP.TransfiereFTP(Fm: TForm): boolean;
begin
with TFtpClient.Create(Fm) do
try
HostName := Servidor;
Port := '21';
UserName := Usuario;
PassWord := Contra;
HostDirName := '';
HostFileName := Origen;
LocalFileName := InterpretarRutaEspecial(Destino);
Binary := Binario;
Passive := Pasivo;
OnRequestDone := FinDeTransmision;
if Descargar then
Result := Receive
else
Result := Transmit;
OnRequestDone := nil;
if Descargar and Borrar then
Delete;
Result := Result and not Error;
Fm.Hide;
if not Result then
ErrorTransmision;
finally
Free;
end;
end;
所以我使用 wireshark 查看了引擎盖,我发现 Indy 的 FTP 没有回复来自服务器的一些消息。
这是与 OverBytes 的文件传输握手 FTP:
我用黄色突出显示了服务器和客户端之间发送的两个开始数据传输的数据包。 现在让我们看看 Indy 的 FTP:
会发生什么服务器正在发送数据包以开始文件传输,但 IdFTP 没有应答。
我见过
发生了什么事?
在 Active 模式传输中,FTP 服务器创建到接收方的传出 TCP 连接。
您的 Wireshark 捕获清楚地表明,有问题的 FTP 服务器正在创建传输连接 BEFORE 发送对 RETR
命令的响应,让您的客户端知道连接正在进行。 TFtpClient
在收到 RETR
响应之前接受该连接。但是 TIdFTP
在接受传输连接之前等待 RETR
响应(这也适用于 TIdFTP
对 STOR
/STOU
/[ 的处理=19=] 命令。
LPortSv.BeginListen; // <-- opens a listening port for transfer
...
SendPort(LPortSv.Binding); // <-- sends the PORT command
...
SendCmd(ACommand, [125, 150, 154]); // <-- sends the RETR command and waits for a response!
...
LPortSv.Listen(ListenTimeout); // <-- accepts the transfer connection
...
重读RFC 959,内容如下:
The passive data transfer process (this may be a user-DTP or a second server-DTP) shall "listen" on the data port prior to sending a transfer request command. The FTP request command determines the direction of the data transfer. The server, upon receiving the transfer request, will initiate the data connection to the port. When the connection is established, the data transfer begins between DTP's, and the server-PI sends a confirming reply to the user-PI.
ICS 是异步的,所以这种情况它处理起来不是什么大问题。但是 Indy 使用阻塞套接字,所以 TIdFTP
需要更新以解决这种情况,可能通过同时监视命令和传输端口,这样它就可以采取相应的行动,而不管传输连接和命令响应的顺序如何到达。
我为此在 Indy 的问题跟踪器中开了一张票:
#300: TIdFTP fails on Active mode transfer connection with vsFTPd
更新: the fix 现在已合并到主代码中。