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 响应(这也适用于 TIdFTPSTOR/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 现在已合并到主代码中。