我正在使用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;
答案 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;