-1

I am using TIdTCPClient to get a file list all works well but when i close the client application and open it again i don't receive any event on TCPServer onExecute though the TIdTCPClient successfully connects to it and i am not able to send the file list.

What am i doing wrong ?

Some code :

procedure TTaifun.csConnected(Sender: TObject);
begin
  cs.IOHandler.WriteLn('FILE_LIST|NOW'); //Sending a request to server for the files
  fname := cs.IOHandler.ReadLn(nil); //Got the file names
  files := ExplodeString(fname,'|'); // Parse the files
end;

procedure TTaifun.svExecute(AContext: TIdContext);
var
  cmds, flist: TStringList;
  i: Integer;
  tmp: string;
  FS : TFileStream;
begin
  CSection.Enter; //Enter critical section
  cmds := ExplodeString(AContext.Connection.IOHandler.ReadLn(nil), '|'); 
  try
    if cmds[0] = 'FILE_LIST' then //Check command received
    begin
      flist := TStringList.Create;
      flist.LoadFromFile(MyPath + 'files.dat');
      tmp := '';
      for i := 0 to flist.Count - 1 do
      begin
          tmp := tmp + flist[i] + ',' + GetFileSize(flist[i]) + ',' +
          BoolToStr(FileExists(MyPath + 'Thumbs\' +
          ChangeFileExt(ExtractFileName(flist[i]), '.thb')),true) + '|'; //Do some parsing
      end;
      AContext.Connection.IOHandler.WriteLn(tmp); //Send the string
    end
 finally
  CSection.Leave; //Leave critical section
 end;
end;
opc0de
  • 11,557
  • 14
  • 94
  • 187
  • See [Remy Lebeau](http://stackoverflow.com/users/65863/remy-lebeau-teamb)'s comment on this [post](http://stackoverflow.com/q/8704912/744588). It's related to TIdHTTP but may give you an insight on the trouble. Precising your Delphi and Indy's versions and providing some code will help people willing to answer your question. – menjaraz Jan 07 '12 at 10:43
  • 1
    Really, you have asked enough questions here to know that nobody can help you if you do not provide more details... like ..., oh I don't know, some code perhaps? – Marjan Venema Jan 07 '12 at 10:49
  • @MarjanVenema I don't like your attitude and i am curious if now you have a solution. – opc0de Jan 07 '12 at 10:55
  • Tough. I don't like the fact that you keep asking questions and wait for someone to ask for more details before providing enough information for someone to help you. In the code you added you don't tell what TTaifun is derived from and whether it is server or client side, or anything else that might help someone help you. Though I can make an educated quess, I am not going to bother, I shouldn't have to... – Marjan Venema Jan 07 '12 at 11:05
  • @MarjanVenema don't bother i shure won't miss anything :) – opc0de Jan 07 '12 at 11:24
  • Don't worry: plenty of other fun things to do :) – Marjan Venema Jan 07 '12 at 11:30
  • .Marjan is a very helpful member here, and opc0de comes across as whiny to me. opc0de; Listen to marjan or else people will stop trying to help you.00.0000 – Warren P Jan 07 '12 at 14:25
  • WarrenP i honestly don't like offtopic mumbeling.It's your problem if you want to help or not.I always give rep to whom diserves it i ask the questions how i like.Please stop posting at my questions you and other who feel like that. – opc0de Jan 07 '12 at 20:48

1 Answers1

3

You are not protecting your critical section from exceptions. When the client disconnects, an exception will be raised by either ReadLn() or WriteLn() (depending on timing) to terminate the thread for that client. The next time the OnExecute event is called for a different thread, the critical section will still be locked and cannot be re-entered again, deadlocking your code. Add a try/finally to your code to guard against that, eg:

procedure TTaifun.svExecute(AContext: TIdContext); 
var 
  ...
begin 
  CSection.Enter; //Enter critical section 
  try
    ...
  finally
    CSection.Leave; //Leave critical section 
  end;
end; 

With that said, why are you using a critical section to begin with? The code you showed is thread-safe by itself, it does not need to be protected from concurrent access:

procedure TTaifun.svExecute(AContext: TIdContext);     
var     
  cmds, flist: TStringList;     
  i: Integer;     
  tmp: string;     
begin     
  cmds := ExplodeString(AContext.Connection.IOHandler.ReadLn, '|');      
  if cmds[0] = 'FILE_LIST' then //Check command received     
  begin     
    tmp := '';     
    flist := TStringList.Create;     
    try
      flist.LoadFromFile(MyPath + 'files.dat');     
      for i := 0 to flist.Count - 1 do     
      begin     
        tmp := tmp + flist[i] + ',' + GetFileSize(flist[i]) + ',' +     
          BoolToStr(FileExists(MyPath + 'Thumbs\' +     
          ChangeFileExt(ExtractFileName(flist[i]), '.thb')),true) + '|'; //Do some parsing     
      end;
    finally
      flist.Free;
    end;     
    AContext.Connection.IOHandler.WriteLn(tmp); //Send the string     
  end;
end;

Alternatively:

procedure TTaifun.svExecute(AContext: TIdContext);     
var     
  cmds, flist: TStringList;     
  i: Integer;     
begin     
  cmds := ExplodeString(AContext.Connection.IOHandler.ReadLn, '|');      
  if cmds[0] = 'FILE_LIST' then //Check command received     
  begin     
    flist := TStringList.Create;     
    try
      flist.LoadFromFile(MyPath + 'files.dat');     
      for i := 0 to flist.Count - 1 do     
      begin     
        flist[i] := flist[i] + ',' + GetFileSize(flist[i]) + ',' +     
          BoolToStr(FileExists(MyPath + 'Thumbs\' +     
          ChangeFileExt(ExtractFileName(flist[i]), '.thb')),true); //Do some parsing     
      end;
      flist.Delimiter := '|';
      flist.StrictDelimiter := True;
      AContext.Connection.IOHandler.WriteLn(flist.DelimitedText); //Send the string     
    finally
      flist.Free;
    end;     
  end;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770