idFTP.Get方法无响应问题

散乱心绪 2008-10-20 11:27:46

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!


...全文
481 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
sibad_sh 2008-11-02
  • 打赏
  • 举报
回复
给你email了
indy控件
散乱心绪 2008-10-29
  • 打赏
  • 举报
回复
帖子放了好久了,看来没人能解答了

现在只好用KillDataChannel的方法做了,虽然麻烦了点。
liuhengwinner 2008-10-21
  • 打赏
  • 举报
回复
我也做过类似的,比 TimeOut设的长一些!
gutiqiang 2008-10-21
  • 打赏
  • 举报
回复
我做了一个fpt下载,每次只能成功下载一个文件,下载第二个文件时就没有响应?不知为什么?
散乱心绪 2008-10-20
  • 打赏
  • 举报
回复
上面的代码少了一部分

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'+#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;
散乱心绪 2008-10-20
  • 打赏
  • 举报
回复
在Get方法里,获取数据的部分是


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,涉及到多线程同步了,是不是有简单点的方法。。。
gutiqiang 2008-10-20
  • 打赏
  • 举报
回复
正好我也遇到一样的问题,没有解决,学习一下。

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧