procedure TThreadFTP.Execute;
begin
inherited;
while (not StartAtOnce) and (not Terminated) do
Sleep(100); Note:= TNote.Create;
Note.FilePath:= ExtractFilePath(Application.ExeName) + 'Note\' + IntToStr(Self.Handle) + '.txt';
try
try
if not Terminated then
DoExec;
except
end; Note.AddLine('DoExec Finished!'+#13#10);
while not Terminated do
Sleep(100);
Note.AddLine('Thread Terminated!'+#13#10);
finally
Note.Free;
end;
end;procedure TThreadFTP.DoExec;
var
FTP: TIdFTP;
RootDIR, RltDIR, File_Name: string; I: Integer;
List: TStringList;
Stream: TStream;
begin
Stream:= TMemoryStream.Create;
List:= TStringList.Create; FTP:= TIdFTP.Create(nil);
try
FTP.Host:= '192.168.0.2'; // FTP地址
FTP.Username:= '**';
FTP.Password:= '**';
FTP.Connect(True, 5000); // 连接
if FTP.Connected then begin
RootDIR:= Utf8ToAnsi( FTP.RetrieveCurrentDir ); // 获取根路径
RltDIR:= '/TextFile/11'; // 设置相对路径
FTP.ChangeDir( AnsiToUtf8( RootDIR+RltDIR ) ); // 切换当前目录
FTP.List(List); // 取当前目录的文件列表,不做该部貌似下面的DirectoryListing无法正常使用
List.Clear; // 清空列表
for I:= 0 to FTP.DirectoryListing.Count - 1 do begin
if Terminated then Exit;
with FTP.DirectoryListing.Items[I] do begin
if ItemType = ditFile then begin // 是文件
File_Name:= Utf8ToAnsi( FileName );
List.Add(File_Name); // 添加文件名到列表
end;
end;
end; while not Terminated do begin
for I:= 0 to List.Count - 1 do begin
if Terminated then Exit;
TMemoryStream(Stream).Clear;
try
Note.AddLine('FTP.Get('+List.Strings[I]+')');
FTP.Get( AnsiToUtf8(RootDIR+RltDIR+'/'+List.Strings[I]), Stream); // 获取文件
Note.AddLine('...Ok'+LRLS);
except
on E: Exception do begin
Note.AddLine('...raise error'+#13#10);
Note.AddLine('errmsg: '+E.Message+#13#10);
raise;
end;
end;
TMemoryStream(Stream).Clear;
end;
end;
end;
finally
Note.AddLine('Free Objects');
Stream.Free;
List.Free;
FTP.Free;
Note.AddLine('...Ok'+#13#10);
end;
end;
我做了个多线程FTP下载测试,目的是为了测试FTP服务器的并发承受能力。线程单元的代码如上。TNote是一个写日志到文件的类。
问题如下:
开启50条线程 循环的去下载FTP上的一个目录中的文件。
开启后,不到半分钟,所有线程都假死了,通过日志文件发现,问题出在了Get方法上(这个时候大概每个线程都已经下载了大约200多次)。
想请教各位大虾,为什么会出现这种情况,是否有方法可以避免。
因为如果Get后立即返回异常 那到还好处理,但如果一直停在Get上 问题就比较大了。
不知道是不是idFTP本身写的不是很稳定的缘故,各位在做FTP的时候都用什么实现的?
ps: 下载时,应该存在多个线程下载同一个文件的情况,貌似FTP应该支持这种下载吧。错误日志如下:
FTP.Get(nr2008100313370782866)...Ok
FTP.Get(nr200810031337109847)...Ok
FTP.Get(nr200810031337118757) // 停在这儿了
--------另外一个------------------------
FTP.Get(nr200810031341199218)...Ok
FTP.Get(nr200810031341470939)...raise error
errmsg: Socket Error # 10093 // 这个返回了错误号
Stream.Free;...Ok
List.Free;...Ok
FTP.Free;...Ok
DoExec Finished!
Thread Terminated!
解决方案 »
- 如何组织这个程序的数组结构
- 主从表更新主键数据! 急急急急急急急急急急急!!!!!
- 如果我的动态创建一个button,想把它的onclick写到一个公共的单元的里,怎么写呀?
- dbvigator 的问题!
- 如何实现随着数据库内容的变化,dbgrid里的东西也变化
- 请教如何设置一个DBGRID的每一栏的宽度?
- 用QUICKREP打印详细内容时怎么能动态设置打印行数!急!!!!!!!!!!!!!!
- 先解决问题者50分。现有一TPageControl(两个TabSheet),上面没有任何控件,希望在程序运行时把Form1,和Form2中的控件分别显示在TPageCotr
- memset(zan_wk,null,sizeof(zan_wk))????
- delphi中的null
- 为什么不能播放RMVB格式的文件?
- 问一个很简单的问题,
for I:= 0 to List.Count - 1 do begin
if Terminated then Exit;
TMemoryStream(Stream).Clear;
try
Note.AddLine('FTP.Get('+List.Strings[I]+')');
FTP.Get( AnsiToUtf8(RootDIR+RltDIR+'/'+List.Strings[I]), Stream);
Note.AddLine('...Ok'+#13#10);
except
on E: Exception do begin
Note.AddLine('...raise error'+#13#10);
Note.AddLine('errmsg: '+E.Message+#13#10);
raise;
end;
end;
TMemoryStream(Stream).Clear;
end;
end;
end;
finally
Note.AddLine('Stream.Free;');
Stream.Free;
Note.AddLine('...Ok'+#13#10);
Note.AddLine('List.Free;');
List.Free;
Note.AddLine('...Ok'+#13#10);
Note.AddLine('FTP.Free;');
FTP.Free;
Note.AddLine('...Ok'+#13#10);
end;
FDataChannel := TIdSimpleServer.Create(nil); try
with TIdSimpleServer(FDataChannel) do begin
InitDataChannel;
BoundIP := (Self.IOHandler as TIdIOHandlerSocket).Binding.IP;
BoundPort := Self.DataPort;
BoundPortMin := Self.DataPortMin;
BoundPortMax := Self.DataPortMax;
BeginListen;
SendPort(Binding);
if AResume then begin
Self.SendCmd('REST ' + IntToStr(ADest.Position), [350]); {Do not translate}
end;
Self.SendCmd(ACommand, [125, 150, 154]); //APR: Ericsson Switch FTP
Listen;
ReadStream(ADest, -1, True); // 估计是这里的问题吧。
end;
finally
FreeAndNil(FDataChannel);
end;
好像socket出现异常后,ReadStream会出现死等的情况。
记得在其他地方看到过,从FTP接收数据,好像有一种模式是服务器向客户端发起连接,并发生数据流,发完后服务端会主动断开连接。
会不会是因为客户端的socket出现异常,导致TIdSimpleServer无法检测到Disconnect事件,结果ReadStream就在那里死等了。刚才发现出现死等后用 KillDataChannel 可以退出死等,不过这样的话必须得在另一个线程里调用 KillDataChannel,涉及到多线程同步了,是不是有简单点的方法