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

时间:2015-06-26 07:09:02

标签: multithreading delphi delphi-2010 sendfile

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

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

procedure TForm17.BtnSendFile(Sender: TObject);
var
 FS: TFileStream;
 filename: string;
begin 
 filetotx := 'temp.jpg';  
 FS := TFileStream.Create(filetotx, fmOpenRead, fmShareDenyWrite);
 FS.Position := 0;
  try
   Form1.IdTCPClient1.Socket.LargeStream := true;
   Form1.IdTCPClient1.Socket.WriteLn('PIC');
   Form1.IdTCPClient1.Socket.Write(FS, 0, true);
  finally
   FS.Free;
  end;
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 := 'PIC_' + datetostr(date) + ' ' + timetostr(time) + '.jpg';
  filename := StringReplace(filename, '/', '-', [rfReplaceAll]);
  filename := StringReplace(filename, ':', '_', [rfReplaceAll]);
  filename := extractfilepath(Application.exename) + 'PIC\' + filename;
  FS := TFileStream.Create(filename, fmCreate);
  FS.Position := 0;
  AContext.Connection.Socket.LargeStream := true;
  AContext.Connection.Socket.ReadStream(FS);
  Jpg := TJpegImage.Create;
  FS.Position := 0;
  Jpg.LoadFromStream(FS);
  form26.image1.Picture.Assign(Jpg);
  try
   Jpg.Free;
   FS.Free;       
  finally
    //send feedback file received
   AContext.Connection.Socket.WriteLn('PICOK');
   TIdNotify.NotifyMethod(form26.Show);
  end;
end;

客户端(收到反馈'PICOK')

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;

1 个答案:

答案 0 :(得分:2)

您的客户端代码正在主UI线程的上下文中发送文件。这就是用户界面冻结的原因 - 在发送繁忙时没有处理任何消息。将该代码移动到工作线程(首选),或者将TIdAntiFreeze组件放到您的表单上。

就实际文件传输而言,您的服务器代码是正常的,但是您的try/finally块是错误的,并且您在不与主UI线程同步的情况下直接访问TImage。您在调用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;