Multithreading 尝试通过tcp/ip发送文件时表单冻结,Delphi 2010

Multithreading 尝试通过tcp/ip发送文件时表单冻结,Delphi 2010,multithreading,delphi,delphi-2010,sendfile,Multithreading,Delphi,Delphi 2010,Sendfile,我面临以下问题。 我和我的一个朋友用uhf数据调制解调器建立了一个无线网络。 当我尝试发送文件(例如照片)并且连接正常时,没有问题。但当我试图发送一个文件时,由于某种原因暂时没有连接,表单会冻结,直到重新建立。有人能帮我吗?下面是我从服务器端和客户端使用的代码(Delphi2010) 客户端(传输文件[如果连接丢失一段时间或永久),此表单将冻结]: 服务器端(接收文件) 客户端(收到反馈“PICOK”) 客户端代码正在主UI线程的上下文中发送文件。这就是UI冻结的原因-在发送繁忙时,没有正在处理

我面临以下问题。 我和我的一个朋友用uhf数据调制解调器建立了一个无线网络。 当我尝试发送文件(例如照片)并且连接正常时,没有问题。但当我试图发送一个文件时,由于某种原因暂时没有连接,表单会冻结,直到重新建立。有人能帮我吗?下面是我从服务器端和客户端使用的代码(Delphi2010)

客户端(传输文件[如果连接丢失一段时间或永久),此表单将冻结]:

服务器端(接收文件)

客户端(收到反馈“PICOK”)


客户端代码正在主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;