Multithreading 尝试通过tcp/ip发送文件时表单冻结,Delphi 2010
我面临以下问题。 我和我的一个朋友用uhf数据调制解调器建立了一个无线网络。 当我尝试发送文件(例如照片)并且连接正常时,没有问题。但当我试图发送一个文件时,由于某种原因暂时没有连接,表单会冻结,直到重新建立。有人能帮我吗?下面是我从服务器端和客户端使用的代码(Delphi2010) 客户端(传输文件[如果连接丢失一段时间或永久),此表单将冻结]: 服务器端(接收文件) 客户端(收到反馈“PICOK”)Multithreading 尝试通过tcp/ip发送文件时表单冻结,Delphi 2010,multithreading,delphi,delphi-2010,sendfile,Multithreading,Delphi,Delphi 2010,Sendfile,我面临以下问题。 我和我的一个朋友用uhf数据调制解调器建立了一个无线网络。 当我尝试发送文件(例如照片)并且连接正常时,没有问题。但当我试图发送一个文件时,由于某种原因暂时没有连接,表单会冻结,直到重新建立。有人能帮我吗?下面是我从服务器端和客户端使用的代码(Delphi2010) 客户端(传输文件[如果连接丢失一段时间或永久),此表单将冻结]: 服务器端(接收文件) 客户端(收到反馈“PICOK”) 客户端代码正在主UI线程的上下文中发送文件。这就是UI冻结的原因-在发送繁忙时,没有正在处理
客户端代码正在主UI线程的上下文中发送文件。这就是UI冻结的原因-在发送繁忙时,没有正在处理的消息。将该代码移动到工作线程中(首选),或者将
tid防冻剂
组件放到表单上
就实际的文件传输而言,您的服务器代码是正常的,但是您的try/finally
块是错误的,您直接访问TImage
,而没有与主UI线程同步。在调用form26.Show
时,您已经在同步,在调用form26.image1.Picture.Assign(Jpg)
时也只需同步即可。请尝试以下方法:
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
S, Filename: string;
FS: TFileStream;
Jpg: TJpegImage;
begin
S := AContext.Connection.Socket.ReadLn;
if S = 'PIC' then
begin
Filename := ExtractFilePath(Application.ExeName) + 'PIC\' + FormatDateTime('"PIC_"mm"-"dd"-"yyyy" "hh"_"nn"_"ss".jpg"', Now);
FS := TFileStream.Create(Filename, fmCreate);
try
AContext.Connection.Socket.LargeStream := true;
AContext.Connection.Socket.ReadStream(FS);
FS.Position := 0;
Jpg := TJpegImage.Create;
try
Jpg.LoadFromStream(FS);
TThread.Synchronize(nil,
procedure
begin
Form26.Image1.Picture.Assign(Jpg);
Form26.Show;
end;
);
finally
Jpg.Free;
end;
finally
FS.Free;
end;
//send feedback file received
AContext.Connection.Socket.WriteLn('PICOK');
end;
end;
或者这个:
type
TMyNotify = class(TIdNotify)
protected
procedure DoNotify; override;
public
Jpg: TJpegImage;
constructor Create;
destructor Destroy; override;
end;
constructor TMyNotify.Create(Stream: TStream);
begin
inherited;
Jpg := TJpegImage.Create;
Jpg.LoadFromStream(Stream);
end;
destructor TMyNotify.Destroy;
begin
Jpg.Free;
inherited;
end;
procedure TMyNotify.DoNotify;
begin
Form26.Image1.Picture.Assign(Jpg);
Form26.Show;
end;
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
S, Filename: string;
FS: TFileStream;
begin
S := AContext.Connection.Socket.ReadLn;
if S = 'PIC' then
begin
Filename := ExtractFilePath(Application.ExeName) + 'PIC\' + FormatDateTime('"PIC_"mm"-"dd"-"yyyy" "hh"_"nn"_"ss".jpg"', Now);
FS := TFileStream.Create(Filename, fmCreate);
try
AContext.Connection.Socket.LargeStream := true;
AContext.Connection.Socket.ReadStream(FS);
FS.Position := 0;
TMyNotify.Create(FS).Notify;
finally
FS.Free;
end;
//send feedback file received
AContext.Connection.Socket.WriteLn('PICOK');
end;
end;
您不能从
TIdTCPServer.OnExecute
事件中访问VCL控件。我已经在表单上删除了一个tidt防冻剂组件,但没有结果。我将尝试使用绝地线程组件,在其中调用以下命令:Form1.IdTCPClient1.Socket.LargeStream:=true;Form1.IdTCPClient1.Socket.WriteLn('PIC');Form1.IdTCPClient1.Socket.Write(FS,0,true);你不需要使用绝地来穿线。Indy有自己的TIdThreadComponent
,或者直接使用Delphi自己的TThread
或TTask
。
type
TReadingThread = class(TThread)
protected
FConn: TIdTCPConnection;
procedure Execute; override;
procedure DoTerminate; override;
public
constructor Create(AConn: TIdTCPConnection); reintroduce;
end;
constructor TReadingThread.Create(AConn: TIdTCPConnection);
begin
TLog.AddMsg('Client Thread Created');
FConn := AConn;
inherited Create(False);
end;
procedure TReadingThread.Execute;
begin
while not Terminated do
begin
if S='MSGOK' then
.
.
else if S = 'PICOK' then
begin
Do Something
end
end;
end;
procedure TReadingThread.DoTerminate;
begin
TLog.AddMsg('Disconnected');
inherited;
end;
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
S, Filename: string;
FS: TFileStream;
Jpg: TJpegImage;
begin
S := AContext.Connection.Socket.ReadLn;
if S = 'PIC' then
begin
Filename := ExtractFilePath(Application.ExeName) + 'PIC\' + FormatDateTime('"PIC_"mm"-"dd"-"yyyy" "hh"_"nn"_"ss".jpg"', Now);
FS := TFileStream.Create(Filename, fmCreate);
try
AContext.Connection.Socket.LargeStream := true;
AContext.Connection.Socket.ReadStream(FS);
FS.Position := 0;
Jpg := TJpegImage.Create;
try
Jpg.LoadFromStream(FS);
TThread.Synchronize(nil,
procedure
begin
Form26.Image1.Picture.Assign(Jpg);
Form26.Show;
end;
);
finally
Jpg.Free;
end;
finally
FS.Free;
end;
//send feedback file received
AContext.Connection.Socket.WriteLn('PICOK');
end;
end;
type
TMyNotify = class(TIdNotify)
protected
procedure DoNotify; override;
public
Jpg: TJpegImage;
constructor Create;
destructor Destroy; override;
end;
constructor TMyNotify.Create(Stream: TStream);
begin
inherited;
Jpg := TJpegImage.Create;
Jpg.LoadFromStream(Stream);
end;
destructor TMyNotify.Destroy;
begin
Jpg.Free;
inherited;
end;
procedure TMyNotify.DoNotify;
begin
Form26.Image1.Picture.Assign(Jpg);
Form26.Show;
end;
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
S, Filename: string;
FS: TFileStream;
begin
S := AContext.Connection.Socket.ReadLn;
if S = 'PIC' then
begin
Filename := ExtractFilePath(Application.ExeName) + 'PIC\' + FormatDateTime('"PIC_"mm"-"dd"-"yyyy" "hh"_"nn"_"ss".jpg"', Now);
FS := TFileStream.Create(Filename, fmCreate);
try
AContext.Connection.Socket.LargeStream := true;
AContext.Connection.Socket.ReadStream(FS);
FS.Position := 0;
TMyNotify.Create(FS).Notify;
finally
FS.Free;
end;
//send feedback file received
AContext.Connection.Socket.WriteLn('PICOK');
end;
end;