Indy10文件传输导致CPU使用率100%
我设法修复了一些断开连接的错误,现在每当文件传输时 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;
i managed to fix some errors with disconnecting, now whenever a file is transferring the CPU Usage becomes 100%, i dunno what im doing wrong :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;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
摆脱Application.ProcessMessages;它不能在主线程以外的线程下调用
Get rid of Application.ProcessMessages; it MUST NOT be called under thread other than main one
您在接收循环中调用 Application.ProcessMessages ,大概是为了防止应用程序的其余部分看起来被冻结。 100% CPU 使用率是一个副作用。
您最好使用 IdAntiFreeze 组件(仍然是一种 hack)或将 ReceiveData 功能放在线程中。
更新:
哎呀。乍一看,我以为这是在主线程中运行的客户端传输,但实际上它是在单独的 IdTcpServer 线程中调用的。在这种情况下,APZ28的建议是正确的;不要在线程中调用Application.ProcessMessages。
You're calling Application.ProcessMessages in your receive loop, presumably to keep the rest of your application from appearing to be frozen. The 100% CPU usage is a side effect.
You're better off using an IdAntiFreeze component (still kind of a hack) or putting the ReceiveData functionality in a thread.
Update:
Whoops. At first glance, I thought this was a client side transfer running in the main thread, but it's actually being called in a separate IdTcpServer thread. In this case, APZ28's advice is correct; don't call Application.ProcessMessages in a thread.
我对 Indy 一无所知(我使用自己的设备,它比 Indy 更轻/更快,用于所有 TCP/IP 客户端/服务器内容 - 请参阅 http://synopse.info),但我猜你的 IdTCPServer1Execute 方法应该在后台线程中运行,但这里的情况并非如此。
所以:
I dont' know anything about Indy (I use my own unit, which is lighter/faster than Indy, for all TCP/IP client/server stuff - see http://synopse.info), but I guess your IdTCPServer1Execute method should run in a background thread, which is not the case here.
So :
如果您不断循环,一个简单的技巧就是在
Application.ProcessMessages
之后添加Sleep(1)
。但也许您可以重新排序代码以阻止 ReadStream 函数,并且仅在接收到合理数量的数据或超时后才运行。
Your looping constantly, an easy hack is to add an
Sleep(1)
after yourApplication.ProcessMessages
.But perhaps you could reorder your code to block on the ReadStream function, and only run when a reasonable amount of data is received, or a timeout has passed.
您和我在 Embarcadero 论坛 (缓存在 CodeNewsFast 上)。
You and I covered this topic in the Embarcadero forums (cached on CodeNewsFast).