Jump to content
Brian Warner

Multiple Simultaneous Connections with TidFTP

Recommended Posts

I'm looking for a kick start in the right direction.  Is it possible to have multiple connections such that I can have more than one file

download going at a time (a cheap version of FileZilla). Many of the software users will find FileZilla too large a leap for their skills. 

 

I presume each one requires its own TidFTP and SSLIOHandler pair. I've playing with putting the set in a TParallel.For loop but get a

general "too many exceptions" in the debugger after a few seconds. Running outside the IDE doesn't give anything more specific 

about what's wrong. 

 

Generally, 

  • Use connection 1 to get file listing.
  • Iterate through the directory listing to create an array of 0..4 of <IdFTP, FileName>. 
  • Go through that list such that up to five GET statements are running.

I've disconnected the events so that there is no updating of controls, i.e., no need to call Synchronize.

 

Thanks for any help.

Brian

Share this post


Link to post

each FTP session, needs: user, password, a file to upload;

then, you need use a way to send this data, like using a "thread", or in your case "n" threads. Each one for a FTP send!

then, each thread will be independent and autonomous each others! needs controls like all works, mainly when any exception occurs!

Edited by programmerdelphi2k

Share this post


Link to post

From the nature of FTP transfers I'm afraid there couldn't be 1 ctrl connection + several data ones. So you'd have to create several fully independent FTP clients

Share this post


Link to post

Thanks for the replies. I think I'm on the right track. I thought about creating "simple" threads,

each with its own TidFTP/SSLHandler pair but thought the TParallel.For loop might speed things along.

 

Here's what I have so far. I'm hoping that "fully independent FTP clients" doesn't mean actually have separate forms, just 

one TidFPT/SSLHander component pair per "client", both setup with the necessary information to do an autologin to the correct 

server. IOW, independently, each does what's intended.

 

type
  TDL = packed record
    FTP : TIdFTP;
    LI : TidFTPListItem;
  end;

var 
  DL := array[0..4] of TDL;

{ Each Cnx is a TidFTP component on the form that has its own SSL handler component }
  Cnx[0] := idFTPDL;
  Cnx[1] := idFTP1;
  Cnx[2] := idFTP2;
  Cnx[3] := idFTP3;
  Cnx[4] := idFTP4;

  Cnx[0].OnWork := nil;  // disables code that updates a TPanel.
  for I := 0 to 4 do
  begin
    if (not Cnx[I].Connected) then
    begin
      Cnx[I].Connect;
    end;
    Cnx[I].OnWork := nil;
  end;

  try
    for I := 0 to 4 do
    begin
      Cnx[I].ChangeDir(ARemoteDir);
    end;

    var Idx : integer := 0;
    var Q : integer := 0;
    SetLength(DL, Idx);

    { Didn't use SetLength(DL, DirCount) since it contains one or more ditDirectory items. 
      This leads to some issues below when distributing the file list to the five FTP 
      components. }

    Cnx[0].List;
    var DirCount := Cnx[0].DirectoryListing.Count;
    for I := 0 to pred(DirCount) do
    begin
      if (Abort) then
      begin
        Exit;
      end;

      LI := Cnx[0].DirectoryListing[I];
      if (LI.ItemType = ditFile) then
      begin
        Idx := Length(DL) + 1;
        SetLength(DL, Idx);
        J := Q mod 5;
        DL[Idx-1].FTP := Cnx[J];
        DL[Idx-1].LI := LI;
        Inc(Q);
      end;
    end;

    { Here's the attempt at TParallel.For, to be replaced by implementing a set of TThread objects.
      I admit that I was learning about TParallel.For on the fly from Nick Hodges' book at 3AM.}
    try
      var LB : integer := Low(DL);
      var HB : integer := High(DL);
      TParallel.For(LB, HB,
        procedure(M : integer)
        begin
          try
            var ADL := DL[M];
            if (Assigned(ADL.FTP) and Assigned(ADL.LI) and ADL.FTP.Connected) then
            begin
              ADL.FTP.Get(ADL.LI.FileName, ALocalDir + ADL.LI.FileName, True);
            end;
          except
            raise;
          end;
      end);
    except
      raise;
    end;

 

Share this post


Link to post

you can see this way:

  • client side:
    • each thread will works like a "separated software"!
    • then, each software should have your credencials, as well as, your file to download/upload
  • server side:
    • it's another history!

Share this post


Link to post

maybe, it would be better some like this:

 

type
	TMyThreadDownload = class(TThread) //.... + all definitions necessary
    private
    	FileToDownload:string; // URL + filename
    protected
    	procedure Execute;
    public
    	constructor Create....
        destructor Destroy;override....
        //
        property FileToDownload:string read FFileToDownload write FFileToDownload;
   	end;
    
implementation

... other definitions

constructor Create;
begin
	FreeOnTerminate:=true; // not use MyThread.Free on button1
end;

procedure TMyThreadDownload.Execute;  // my sample to HTTP, but you can port it to FTP class!!!
var
	MyClientHttp: TIdHTTP; //or any other class to downloads
    MyIOHandler:TIdSSLIOHandlerSocketOpenSSL;
    MyStream:TFileStream;
begin
	// create IOHandler + definitions
    // create MyClientHtpp + definitions
    // create your MyStream + definitions
	try 
	    try
	    	MyClientHttp.Get( FFileToDownload, MyStream);
            //
            MyStream.SaveToFile('...');
	    except
	    // what to do ?
	    end;
	finally
	 // release objects created
	end;   
end;

then, you usage:

 

Button1 click:

var
	MyThread:TMyThreadDownload;
begin
// if you want on loop, then just loop it!
//
	MyyThread:=TMyThreadDownload.Create;
    MyThread.FileToDownload:= 'xxx';
    MyThread.Start;
end;

 

Edited by programmerdelphi2k

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×