2

I am testing IndyFTP to upload a file to a server. The file is uploaded but has 0 bytes because there is a EIdAccessTimeout exception - 'Accept timed out". How can I prevent the exception? Is my code incorrect? The code is shown below:

procedure TForm1.FTPUpload1Click(Sender: TObject);
{ Indy FTP Upload. }
var
  iHost: string;
  iUsername: string;
  iPassword: string;
  iFolder: string;
  iSourceFile: string;
  iDestFile: string;
  iAppend: boolean;
  iStartPos: Int64;
begin
  iHost := FTPHost1.Text;
  iUsername := Username1.Text;
  iPassword := Password1.Text;
  iFolder := ServerFolder1.Text;
  if FileExists(SourceFile1.Text) then
    iSourceFile := SourceFile1.Text
  else
    Exit;
  if FileExists(SourceFile1.Text) then
    iDestFile := ExtractFileName(SourceFile1.Text)
  else
    Exit;
  iAppend := False;
  iStartPos := -1;
  IdFTP1.Host := iHost;
  IdFTP1.Username := iUsername;
  IdFTP1.Password := iPassword;
  IdFTP1.Connect;
  IdFTP1.TransferType := ftBinary;
  IdFTP1.Put(iSourceFile);
  IdFTP1.Disconnect;
end;

There are some unused vars listed because I am just learning and have not used some of the parameters yet.

Bill
  • 2,993
  • 5
  • 37
  • 71

1 Answers1

3

Most likely, your FTP client is set to ACTIVE mode, so this error means that after a successful login to the FTP server, the "reverse" connection couldn't be established (the file transfer).

In active mode FTP the client connects from a random unprivileged port (N > 1023) to the FTP server's command port, port 21. Then, the client starts listening to port N+1 and sends the FTP command PORT N+1 to the FTP server. The server will then connect back to the client's specified data port from its local data port, which is port 20.

Active FTP vs. Passive FTP, a Definitive Explanation

You can set to passive mode this way:

IdFTP1.Passive := True;

EDIT

In addition, use try-except-finally blocks, so you can do some error handling. Something like:

  try
    IdFTP1.Connect;
    try
      IdFTP1.Put(...);
    finally
      IdFTP1.Disconnect;
    end;
  except
    // couldn't connect
  end;
Peter Kostov
  • 941
  • 1
  • 6
  • 15
  • Thanks Peter. Once I added IdFTP1.Passive := True the file uploaded correctly. Would the try finally blocks be around Connect and Put? – Bill Aug 26 '14 at 16:50
  • **Connect** can raise an exception, so it must be inside a try block. Technically, **Put** can raise an exception too (when the destination file name is empty) and it should be secured too. Also, if **Connect** raises an E, **Disconnect** is called automatically. Finally, after the content for the transfer operation has been sent successfully, **AfterPut** event handler is called. – Peter Kostov Aug 26 '14 at 17:08
  • If you use `try/finally` to close the connection, put the `Connect()` **before** the `try` and put the `Disconnect()` **inside** the `finally`. Do not put the `Connect()` **inside** the `try`. There is no need to call `Disconnect()` if `Connect()` raises an exception, `Connect()` handles that internally. You would only need to call `Disconnect()` if `Put()` raises an exception. It would make sense to put `Connect()` **inside** a `try` if you are using `try/except` instead. – Remy Lebeau Aug 26 '14 at 17:49
  • Thanks Remy, I used the latter try/except block. – Bill Aug 26 '14 at 18:16