第二次连接时TIdTCPServer卡住了

时间:2012-01-07 09:33:53

标签: delphi indy

我正在使用TIdTCPClient获取文件列表一切正常但是当我关闭客户端应用程序并再次打开它时,我没有收到TCPServer onExecute上的任何事件,尽管TIdTCPClient成功连接到它并且我无法发送文件列表。

我做错了什么?

一些代码:

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;

1 个答案:

答案 0 :(得分:3)

您没有保护您的关键部分免受例外影响。当客户端断开连接时,ReadLn()WriteLn()(取决于时间)将引发异常以终止该客户端的线程。下次为另一个线程调用OnExecute事件时,关键部分仍将被锁定,无法再次重新输入,从而导致代码死锁。在代码中添加try/finally以防范,例如:

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

话虽如此,你为什么要使用一个关键部分开始?您展示的代码本身就是线程安全的,不需要保护它不受并发访问的影响:

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;

可替换地:

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;