当互联网变慢时,TIdHttp会冻结

时间:2014-01-20 03:28:51

标签: delphi delphi-2009 indy

当互联网变慢或没有连接时,如何避免冻结idHTTP。我的申请冻结,我甚至无法关闭表格。

这是我设置代码的方式

procedure TDownloader.IdHTTPWork(ASender: TObject; AWorkMode: TWorkMode;
  AWorkCount: Int64);
var
  lwElapsedMS: LongWord;
  iBytesTransferred: Int64;
  iBytesPerSec: Int64;
  iRemaining: Integer;
begin
  if AWorkMode <> wmRead then Exit;

  lwElapsedMS := GetTickDiff(FLastTicks, Ticks);
  if lwElapsedMS = 0 then lwElapsedMS := 1; // avoid EDivByZero error

  if FTotalBytes > 0 then
    FPercentDone := Round(AWorkCount / FTotalBytes * 100.0)
  else
    FPercentDone := 0;

  iBytesTransferred := AWorkCount - FLastWorkCount;

  iBytesPerSec := Round(iBytesTransferred * 1000 / lwElapsedMS);

  if Assigned(OnDownloadProgress) then
  begin
    if FContinueDownload <> 0 then //previous file downloaded
    begin
      iRemaining := 100 - FContinueDownload;
      iRemaining := Round(FPercentDone * iRemaining / 100);
      OnDownloadProgress(Self, FContinueDownload + iRemaining, AWorkCount, FTotalBytes, iBytesPerSec);
    end else
      OnDownloadProgress(Self, FPercentDone, AWorkCount, FTotalBytes, iBytesPerSec);
  end;

  FLastWorkCount := AWorkCount;
  FLastTicks := Ticks;

  if FCancel then
  begin
    Abort;
    TidHttp(ASender).Disconnect;
  end;
end;

procedure TDownloader.IdHTTPWorkBegin(ASender: TObject; AWorkMode: TWorkMode;
  AWorkCountMax: Int64);
begin
  if AWorkMode <> wmRead then Exit;

  FPercentDone := 0;
  FTotalBytes := AWorkCountMax;
  FLastWorkCount := 0;
  FLastTicks := Ticks;
end;

procedure TDownloader.IdHTTPWorkEnd(ASender: TObject; AWorkMode: TWorkMode);
begin
  if AWorkMode <> wmRead then Exit;
  if Assigned(OnDownloadComplete) and (FPercentDone >= 100) then
    OnDownloadComplete(Self)
  else if Assigned(OnDownloadCancel) then
    OnDownloadCancel(Self);
end;

function TDownloader.EXDownload(AURL, ADestFile: String;
  AAutoDisconnect: Boolean): Boolean;
var
  fsBuffer: TFileStream;
  idHttp: TIdHttp;
begin
  if FileExists(ADestFile) then
    fsBuffer := TFileStream.Create(ADestFile, fmOpenReadWrite)
  else
    fsBuffer := TFileStream.Create(ADestFile, fmCreate);

  fsBuffer.Seek(0, soFromEnd);
  try
    idHttp := TIdHttp.Create(nil);
    idHttp.OnWorkBegin := idHttpWorkBegin;
    idHttp.OnWork := idHttpWork;
    idHttp.OnWorkEnd := idHttpWorkEnd;
    idHttp.Request.CacheControl := 'no-store';
    try
      ...
      idHttp.Get(AURL, fsBuffer);
      ...
    finally
      idHttp.Free;
    end;
  finally
    fsBuffer.Free;
  end;
end;

......

procedure TDownloader.Execute;
begin
  Inherited;
  while not Terminated do
  begin
    if FUrl <> '' then
    begin
      EXDownload(FUrl, FFilename, True);
    end;
  end;
end;

... 关于主要表格进展

procedure TfrmDownloadList.DownloadProgress(Sender: TObject; aPercent:Integer;
    aProgress, aProgressMax, aBytesPerSec: Int64);
var
  yts: PYoutubeSearchInfo;
begin
  if Assigned(FCurrentDownload) then
  begin
    yts := vstList.GetNodeData(FCurrentDownload);
    yts.Tag := aPercent;
    ProgressBar.Position := aPercent;
    vstList.InvalidateNode(FCurrentDownload);
    StatusBar.Panels.Items[1].Text := 'Download: ' + FormatByteSize(aProgress) + '/' +
      FormatByteSize(aProgressMax);
    StatusBar.Panels.Items[2].Text := 'Speed: ' + FormatByteSize(aBytesPerSec) + 'ps';
    Application.ProcessMessages;
  end;
end;

当互联网只有在因信号不良而掉线时才有问题我没有问题。 这是我的应用lookslike

2 个答案:

答案 0 :(得分:2)

如果我们假设TDownloader.OnDownloadProgress被分配给TfrmDownloadList.DownloadProgress方法,那么你的问题是你从一个辅助线程(即不是来自主线程)调用VCL代码(你的进度条更新) 。这不受支持。

您需要使用线程内的Synchronize语句来包装调用。同步调用主线程上的无参数方法。因此,您需要存储所需的变量,然后在TDownloader类中的方法上调用Synchronize,然后调用TfrmDownloadList.DownloadProgress

你不能直接或间接地从在主线程之外的另一个线程上运行的代码中调用TfrmDownloadList.DownloadProgress,因为它更新了VCL对象,并且VCL不是线程安全的。

对于您的DownloadComplete事件也是如此,如果它更新任何VCL对象......

答案 1 :(得分:0)

你使用TIdAntiFreeze怎么样?

  

TIdAntiFreeze实现了一个确保的GUI集成类   处理器时间是为Application主线程分配的。

     

Indy适用于阻塞套接字模型。调用方法中的方法   Indy组件在完成之前不会返回。如果是电话   在主线程中,这将导致应用程序用户   Indy调用期间“冻结”的界面。 TIdAntiFreeze抵消了   这个效果。

     

TIdAntiFreeze允许Indy处理应用程序消息   Indy阻塞套接字时继续执行Windows消息   电话有效。

     

只有一个TIdAntiFreeze可以在应用程序中处于活动状态。