3

我设法通过断开连接修复了一些错误,现在每当文件传输时 CPU 使用率变为 100%,我不知道我做错了什么:S.....

const
 MaxBufferSize = 1024;

type
 TClient = class(TObject)
 public
  AContext: TIdContext;
  FileSize: Integer;
  Canceled: Boolean;
  Transfered: Integer;
  procedure ReceiveData;
  procedure Update;
 end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
 Data: string;
 Client: TClient;
 Item: TListItem;
begin
 Data := AContext.Connection.IOHandler.ReadLn;

 //Data := 'SEND|785548' = Command + | + FileSize
 if Copy(Data, 1, 4) = 'SEND' then
 begin
  Delete(Data, 1, 5);
  Client := TClient.Create;
  Client.FileSize := StrToInt(Data);
  Client.AContext := AContext;
  Item := ListView1.Items.Add;
  Item.Caption := AContext.Connection.Socket.Binding.PeerIP;
  Item.Data := Client;
  Client.ReceiveData;
 end;
end;

procedure TClient.ReceiveData;
var
 currRead : Integer;
 FS: TFileStream;
begin
 Canceled := False;
 FS := TFileStream.Create('C:\Test.dat', fmCreate or fmOpenReadWrite);
 FS.Size := 0;
 Transfered := 0;
 try
  while (FS.Position < FileSize) and (Athread.Connection.Connected) and (not Canceled) do
  begin
   Application.ProcessMessages;
   if (FileSize - FS.Position) >= MaxBufferSize then currRead := MaxBufferSize
   else currRead := (FileSize - FS.Position);
   AThread.Connection.IOHandler.ReadStream(FS, CurrRead);
   Transfered := FS.Position;
   Notify.NotifyMethod(Update);
   Application.ProcessMessages;
  end;
 finally
  FS.Free;
  AThread.Connection.IOHandler.InputBuffer.Clear;
  AThread.Connection.Disconnect;
  AThread.RemoveFromList;
  Notify.NotifyMethod(Update);
  Application.ProcessMessages;
 end;
end;

procedure TClient.Update;
begin
 //Code to Display Progress bar and stuff (Simplified for now)
 Form1.Label1.Caption := 'Transfered Data : ' + IntToStr(Transfered);
end;
4

5 回答 5

6

摆脱 Application.ProcessMessages;它不能在主线程以外的线程下调用

于 2010-11-14T15:23:52.330 回答
4

您在接收循环中调用 Application.ProcessMessages ,大概是为了防止应用程序的其余部分看起来被冻结。100% CPU 使用率是一个副作用。

您最好使用 IdAntiFreeze 组件(仍然是一种 hack)或将 ReceiveData 功能放在线程中。

更新:

哎呀。乍一看,我以为这是在主线程中运行的客户端传输,但实际上它是在单独的 IdTcpServer 线程中调用的。在这种情况下,APZ28 的建议是正确的;不要在线程中调用 Application.ProcessMessages。

于 2010-11-14T14:03:19.860 回答
2

我对 Indy 一无所知(对于所有 TCP/IP 客户端/服务器的东西,我使用自己的单元,它比 Indy 更轻/更快 - 请参阅http://synopse.info),但我猜你的 IdTCPServer1Execute 方法应该运行在后台线程中,这里不是这种情况。

所以 :

  1. 摆脱所有那些 Application.ProcessMessages 等;
  2. 使用计时器来同步您的 UI(一秒钟刷新读取传输的字节数就足够了),而不是 Notify() 或 Synchronize() 方法;
  3. 确保您的 IdTCPServer1 组件在单独的线程中运行(应该有一些属性可以做到这一点);
  4. 另一种可能性(非常不可能)是不必像这样调用 ReadStream 方法,也不必以 CPU 友好的方式等待数据;如果是这种情况,Indy 应该提供一些方法来等待待处理的数据,而不会阻塞。
  5. 使用分析器(周围有一些免费的——比如http://delphitools.info)来猜测你的 CPU 被烧毁的地方。
  6. 在 IDE 之外运行 - 行为是否相同?
于 2010-11-15T07:17:49.163 回答
1

你和我在Embarcadero 论坛缓存在 CodeNewsFast 上)中讨论了这个主题。

于 2010-11-18T03:30:10.663 回答
1

你不断循环,一个简单的技巧是Sleep(1)在你的Application.ProcessMessages.

但也许您可以重新排序代码以阻止 ReadStream 函数,并且仅在接收到合理数量的数据或超时时运行。

于 2010-11-14T14:13:24.113 回答