从Socket收到错误消息:“位图图像无效”

时间:2013-11-29 20:33:27

标签: delphi sockets bitmap file-transfer serversocket

我正在尝试使用ClientSocket和ServerSocket组件获取屏幕截图并通过Web发送。

当我尝试将ServerSocket收到的流再次转换为图片时,我遇到了问题。错误消息“位图图像无效!”表演时: DesktopForm.imgScreen.Picture.Bitmap.LoadFromStream(ms);

我不知道问题是在发送图像的方式还是妨碍了。

我的服务器代码:

unit UntThreadDesktop;

interface

uses
  System.Classes,
  System.SysUtils,
  System.Win.ScktComp,
  WinApi.Windows,
  WinApi.ActiveX,
  Vcl.Graphics,
  Vcl.Imaging.Jpeg,
  UntDesktopForm;

type
  TThreadDesktop = class(TThread)
  private
    FSocket: TCustomWinSocket;
    FDesktopForm: TDesktopForm;
  public
    constructor Create(ASocket: TCustomWinSocket);
    destructor Destroy; override;
    procedure Execute; override;
  end;

implementation

uses
  UntLibraries;

{ TThreadDesktop }

constructor TThreadDesktop.Create(ASocket: TCustomWinSocket);
begin
  inherited Create(true);
  FreeOnTerminate := true;
  FSocket := ASocket;
end;

destructor TThreadDesktop.Destroy;
begin
  inherited;
end;

procedure TThreadDesktop.Execute;
var
  text: string;
  fileSize: integer;
  ms: TMemoryStream;
  buf: Pointer;
  nBytes: integer;
  jpg: TJPEGImage;
begin
  inherited;
  CoInitialize(nil);
  try

    // Init DesktopForm
    Synchronize(procedure  begin
      FDesktopForm := TDesktopForm.Create;
      FDesktopForm.Show;
    end);

    ms := TMemoryStream.Create;

    try

      FSocket.SendText('<|GetScreen|>');
      while FSocket.Connected and (not Self.Terminated) and (FDesktopForm <> nil) do
      begin

        if FSocket.ReceiveLength > 0 then
        begin

          ms.Clear;

          text := string(FSocket.ReceiveText);
          text := Copy(text,1, Pos(#0,text)-1);
          fileSize := StrToInt(text);

          // Receiving file
          while FSocket.Connected and (not Self.Terminated) and (FDesktopForm <> nil) do
          begin
            Synchronize(procedure begin
              if FDesktopForm <> nil then
                FDesktopForm.panInfo.Caption := 'Total: ' + IntToStr(ms.Size) +
                ' de ' + IntToStr(fileSize);
            end);

            try
              text := '';
              GetMem(buf, FSocket.ReceiveLength);
              try
                nBytes := FSocket.ReceiveBuf(buf^, FSocket.ReceiveLength);
                if nBytes > 0 then
                  ms.Write(buf^, nBytes);
                if (ms.Size = fileSize) or (nBytes <= 0) then
                begin
                  ms.Position := 0;
                  ms.SaveToFile('C:\Temp\Screen.bmp');
                  ms.Position := 0;
                  //jpg := TJPEGImage.Create;
                  //jpg.LoadFromStream(ms);
                  // Carrega a imagem
                  Synchronize(procedure begin
                    if FDesktopForm <> nil then
                      //FDesktopForm.imgScreen.Picture.Assign(jpg);
                      FDesktopForm.imgScreen.Picture.Graphic.LoadFromStream(ms);
                  end);
                end;
              finally
                FreeMem(buf);
              end;
            except
            end;
          end;

        end;

        TThread.Sleep(10);
      end;

    finally
      ms.Free;

      // Close DesktopForm
      Synchronize(procedure begin
        if FDesktopForm <> nil then
          FDesktopForm.Close;
      end);
    end;

  finally
    CoUninitialize;
  end;
end;

end.

这是一个用于在后台接收图像的线程。

在我的应用程序服务器的主要形式中,我拥有一个使用ServerType属性的TServerSocket组件到stThreadBlocking。

在我的客户端应用程序中,我使用属性ClientType作为ctNonBlocking的TClientSocket组件。

我的线程代码:

unit UntThreadDesktopClient;

interface

uses
  System.Classes,
  System.SysUtils,
  System.Win.ScktComp,
  WinApi.Windows,
  WinApi.ActiveX,
  Vcl.Imaging.Jpeg,
  Vcl.Graphics,
  Vcl.Forms;

type
  TThreadDesktopClient = class(TThread)
  private
    FSocket: TClientSocket;
    FStream: TMemoryStream;
  public
    constructor Create(AHostname: string; APort: integer); reintroduce;
    destructor Destroy; override;
    procedure Execute; override;
  private
    procedure OnConnect(Sender: TObject; Socket: TCustomWinSocket);
    procedure GetScreen(stream: TMemoryStream);
  end;

implementation

{ TThreadDesktopClient }

constructor TThreadDesktopClient.Create(AHostname: string; APort: integer);
begin
  inherited Create(true);
  FreeOnTerminate := true;

  FStream := TMemoryStream.Create;

  FSocket := TClientSocket.Create(nil);
  FSocket.ClientType := ctNonBlocking;
  FSocket.Host := AHostname;
  FSocket.Port := APort;
  FSocket.OnConnect := OnConnect;
  FSocket.Open;
end;

destructor TThreadDesktopClient.Destroy;
begin
  FStream.Free;
  if FSocket.Active then
    FSocket.Close;
  FSocket.Free;
  inherited;
end;

procedure TThreadDesktopClient.Execute;
var
  cmd: AnsiString;
begin
  inherited;
  CoInitialize(nil);
  try
    while FSocket.Active and not Self.Terminated do
    begin
      if FSocket.Socket.ReceiveLength > 0 then
      begin
        cmd := FSocket.Socket.ReceiveText;
        if cmd = '<|GetScreen|>' then
        begin
          FStream.Clear;
          GetScreen(FStream);
          FStream.Position := 0;
          FSocket.Socket.SendText(AnsiString(IntToStr(FStream.Size)) + #0);
          FSocket.Socket.SendStream(FStream);
        end
        else
        if cmd = '<|TYPE|>' then
        begin
          FSocket.Socket.SendText('<|TYPE-DESKTOP|>');
        end;
      end;
    end;
  finally
    CoUninitialize;
  end;
end;

procedure TThreadDesktopClient.OnConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  Start;
end;

procedure TThreadDesktopClient.GetScreen(stream: TMemoryStream);
var
  DC: HDC;
  bmp: TBitmap;
  jpg: TJPEGImage;
begin
  DC := GetDC(GetDesktopWindow);
  try
    bmp := TBitmap.Create;
    jpg := TJPEGImage.Create;
    try
      //bmp.PixelFormat := pf8bit;
      bmp.Width := GetDeviceCaps(DC, HORZRES);
      bmp.Height := GetDeviceCaps(DC, VERTRES);
      //bmp.Width := Screen.Width;
      //bmp.Height := Screen.Height;
      BitBlt(bmp.Canvas.Handle, 0, 0, bmp.Width, bmp.Height, DC, 0, 0, SRCCOPY);
      bmp.Modified := True;
      //jpg.Assign(bmp);
      //jpg.Compress;
      stream.Clear;
      //jpg.SaveToStream(stream);
      bmp.SaveToStream(stream);
    finally
      bmp.Free;
      jpg.Free;
    end;
  finally
    ReleaseDC(GetDesktopWindow, DC);
  end;
end;

end.

为了进一步说明,我还将发布我的客户端应用程序的主线程以及如何从我的客户端应用程序在主窗体中调用它。

unit UntThreadMain;

interface

uses
  System.Classes,
  System.Win.ScktComp,
  WinApi.ActiveX;

type
  TThreadMain = class(TThread)
  private
    FClientSocket: TClientSocket;
  public
    constructor Create(AHostname: string; APort: integer); reintroduce;
    destructor Destroy; override;
    procedure Execute; override;
  public
    procedure OnConnect(Sender: TObject; Socket: TCustomWinSocket);
    procedure OnDisconnect(Sender: TObject; Socket: TCustomWinSocket);
    procedure OnError(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
  private
    procedure SendInfo;
    procedure OpenDesktopChannel;
  end;

implementation

uses
  UntClientMainForm,
  UntThreadDesktopClient;

{ TThreadMain }

constructor TThreadMain.Create(AHostname: string; APort: integer);
begin
  inherited Create(true);
  FreeOnTerminate := false;
  FClientSocket := TClientSocket.Create(nil);
  FClientSocket.ClientType := ctNonBlocking;
  FClientSocket.Host := AHostname;
  FClientSocket.Port := APort;
  FClientSocket.OnConnect := OnConnect;
  FClientSocket.OnDisconnect := OnDisconnect;
  FClientSocket.Open;
end;

destructor TThreadMain.Destroy;
begin
  if FClientSocket.Active then
    FClientSocket.Close;
  FClientSocket.Free;
  inherited;
end;

procedure TThreadMain.Execute;
var
  cmd: AnsiString;
begin
  inherited;
  CoInitialize(nil);
  try
    while FClientSocket.Socket.Connected and not Self.Terminated do
    begin
      if FClientSocket.Socket.ReceiveLength > 0 then
      begin
        cmd := FClientSocket.Socket.ReceiveText;
        if cmd = '<|TYPE|>' then
          FClientSocket.Socket.SendText('<|TYPE-COMMAND|>')
        else
        if cmd = '<|INFO|>' then
          SendInfo
        else
        if cmd = '<|REQUEST-DESKTOP|>' then
          TThreadDesktopClient.Create(FClientSocket.Host, FClientSocket.Port);
      end;
    end;
  finally
    CoUninitialize;
  end;
end;

procedure TThreadMain.OnConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  Start;
  Synchronize(procedure
  begin
    ClientMainForm.stBar.Panels[1].Text := 'Conectado';
    ClientMainForm.btnConectar.Caption := 'Desconectar';
  end);
end;

procedure TThreadMain.OnDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  Synchronize(procedure
  begin
    ClientMainForm.stBar.Panels[1].Text := 'Desconectado';
    ClientMainForm.btnConectar.Caption := 'Conectar';
  end);
end;

procedure TThreadMain.OnError(Sender: TObject; Socket: TCustomWinSocket;
  ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
  ErrorCode := 0;
end;

procedure TThreadMain.SendInfo;
var
  cmd: AnsiString;
begin
  cmd := '<|INFO|>;NomePC=Tiago-PC;SO=Windows Seven Professiona 64-bit;' +
    'CPU=Intel Core i7 3ª Geração';
  FClientSocket.Socket.SendText(cmd);
end;

end.

请注意,此线程调用TThreadDesktopClient。

在应用服务器的主窗体中,TServerSocket以这种方式获取OnGetThread TServerSocket的方法:

procedure TMainForm.ServerSocketGetThread(Sender: TObject;
  ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread);
begin
  SocketThread := TThreadController.Create(false, ClientSocket);
end;

请求图片时:

procedure TMainForm.pmiAcessarClick(Sender: TObject);
var
  nI: integer;
begin
  for nI := 0 to Pred(ServerSocket.Socket.ActiveConnections) do
  begin
    if ServerSocket.Socket.Connections[nI].SocketHandle = cdsClientesId.AsInteger then
      ServerSocket.Socket.Connections[nI].SendText('<|REQUEST-DESKTOP|>');
  end;
end;

返回我的客户端应用程序,此代码用于连接服务器(TServerSocket)。

procedure TClientMainForm.btnConectarClick(Sender: TObject);
begin
  if FThreadMain = nil then
  begin
    FThreadMain := TThreadMain.Create('localhost', 6550);
  end
  else
  begin
    FThreadMain.Terminate;
    FThreadMain.Free;
    FThreadMain := nil;
  end;
end;

所以,这就是我的所有代码 收到图像后,我尝试将其加载到TImage上,得到错误消息:“位图图像无效。”

我尝试了几种不同的方法来处理客户端应用程序发送的流。但它仍然失败 通常会得到相同的错误:“位图图像无效。”

1 个答案:

答案 0 :(得分:2)

您展示的代码存在 LOT 问题 - 从基本上缺乏对TClientSocketTServerSocket实际上如何工作的理解,到缺乏了解如何通过TCP / IP发送/接收/解析。我看到你的代码中很少有正确的东西。

您正在客户端创建多个连接,使每个连接都识别其类型(命令与桌面),但您的服务器代码不是查询该类型,甚至不关心类型是什么。它假定每个客户端都是桌面客户端并询问其屏幕。因此,您可以通过简单地消除第二个连接来简化双方的代码。反正并不是真的需要它。您可以将连接保持在最低限度,以减少开销。

我强烈建议重新编写代码。

尝试更像这样的东西:

普通的:

unit UntSocketCommon;

uses
  System.Classes,
  System.Win.ScktComp;

interface

procedure ReadRawFromSocket(Socket: TWinSocketStream; Buf: Pointer; BufLen: Integer);
function ReadLineFromSocket(Socket: TWinSocketStream): String;
function ReadIntegerFromSocket(Socket: TWinSocketStream): Integer;
procedure ReadStreamFromSocket(Socket: TWinSocketStream; Stream: TStream);

procedure WriteRawFromSocket(Socket: TWinSocketStream; Buf: Pointer; BufLen: Integer);
procedure WriteLineToSocket(Socket: TWinSocketStream; const Value: String);
procedure WriteIntegerToSocket(Socket: TWinSocketStream; Value: Integer);
procedure WriteStreamToSocket(Socket: TWinSocketStream; Stream: TStream);

implementation

procedure ReadRawFromSocket(Socket: TWinSocketStream; Buf: Pointer; BufLen: Integer);
var
  PBuf: PByte;
  nBytesRead: Integer;
begin
  PBuf := PByte(Buf);
  while BufLen > 0 do
  begin
    nBytesRead := Socket.Read(PBuf^, BufLen);
    if nBytesRead < 1 then raise Exception.Create('Unable to read from socket');
    Inc(PBuf, nBytesRead);
    Dec(BufLen, nBytesRead);
  end;
end;

function ReadLineFromSocket(Socket: TWinSocketStream): String;
var
  Ch: AnsiChar;
  Buf: array[0..255] of AnsiChar;
  BufLen: Integer;
  S: UTF8String;

  procedure AppendBuf;
  var
    OldLen: Integer;
  begin
    OldLen := Length(S);
    SetLength(S, OldLen + BufLen);
    Move(Buf[0], S[OldLen], BufLen);
  end;

begin
  Result := '';
  BufLen := 0;
  repeat
    ReadRawFromSocket(Socket, @Ch, SizeOf(Ch));
    if Ch = #10 then Break;
    if BufLen = Length(Buf) then
    begin
      AppendBuf;
      BufLen := 0;
    end;
    Buf[BufLen] := Ch;
    Inc(BufLen);
  until False;
  if BufLen > 0 then AppendBuf;
  BufLen := Length(S);
  if BufLen > 0 then
  begin
    if S[BufLen] = #13 then
      SetLength(S, BufLen-1);
  end;
  Result := String(S);
end;

function ReadIntegerFromSocket(Socket: TWinSocketStream): Integer;
begin
  ReadRawFromSocket(Socket, @Result, SizeOf(Result));
  Result := ntohl(Result);
end;

procedure ReadStreamFromSocket(Socket: TWinSocketStream; Stream: TStream);
var
  Size: Integer;
  Buf: array[0..1023] of Byte;
  nBytes: Integer;
begin
  Size := ReadIntegerFromSocket(Socket);
  while Size > 0 do
  begin
    nBytes := Size;
    if nBytes > Length(Buf) then nBytes := Length(Buf);
    ReadRawFromSocket(Socket, Buf[0], nBytes);
    Stream.WriteBuffer(Buf[0], nBytes);
    Dec(Size, nBytes);
  end;
end;

procedure WriteRawToSocket(Socket: TWinSocketStream; Buf: Pointer; BufLen: Integer);
var
  PBuf: PByte;
  nBytesWritten: Integer;
begin
  PBuf := PByte(Buf);
  while BufLen > 0 do
  begin
    nBytesWritten := Socket.Write(PBuf^, BufLen);
    if nBytesWritten < 1 then raise Exception.Create('Unable to write to socket');
    Inc(PBuf, nBytesWritten);
    Dec(BufLen, nBytesWritten);
  end;
end;

procedure WriteLineToSocket(Socket: TWinSocketStream; const Value: String);
var
  S: UTF8String;
begin
  S := UTF8String(Value + #13#10);
  WriteRawToSocket(Socket, PAnsiChar(S), Length(S));
end;

procedure WriteIntegerToSocket(Socket: TWinSocketStream; Value: Integer);
begin
  Value := htonl(Value);
  WriteRawToSocket(Socket, @Value, SizeOf(Value));
end;

procedure WriteStreamToSocket(Socket: TWinSocketStream; Stream: TStream);
var
  Size: Integer;
  Buf: array[0..1023] of Byte;
  nBytes: Integer;
begin
  Size := Stream.Size - Stream.Position;
  WriteIntegerToSocket(Socket, Size);
  while Size > 0 do
  begin
    nBytes := Size;
    if nBytes > Length(Buf) then nBytes := Length(Buf);
    Stream.ReadBuffer(Buf[0], nBytes);
    WriteRawToSocket(Socket, Buf[0], nBytes);
    Dec(Size, nBytes);
  end;
end;

end.

服务器:

unit UntThreadDesktop;

interface

uses
  System.Classes,
  System.Win.ScktComp,
  UntDesktopForm;

type
  TThreadController = class(TServerClientThread)
  private
    FDesktopForm: TDesktopForm;
  protected
    procedure ClientExecute; override;
  end;

implementation

uses
  System.SysUtils,
  WinApi.Windows,
  Vcl.Graphics,
  UntLibraries,
  UntSocketCommon;

{ TThreadDesktop }

procedure TThreadController.ClientExecute;
var
  fileSize: Integer;
  ms: TMemoryStream;
  buf: array[0..1023] of Byte;
  nBytes: Integer;
  SocketStrm: TWinSocketStream;
begin
  SocketStrm := TWinSocketStream.Create(ClientSocket, 5000);
  try
    // Init DesktopForm
    Synchronize(
      procedure
      begin
        FDesktopForm := TDesktopForm.Create;
        FDesktopForm.Show;
      end
    );

    try
      ms := TMemoryStream.Create;
      try
        while ClientSocket.Connected and (not Terminated) and (FDesktopForm <> nil) do
        begin
          ms.Clear;

          WriteLineToSocket(SocketStrm, '<|GetScreen|>');

          {
          ReadStreamFromSocket(SocketStrm, ms);
          ms.Position := 0;
          ms.SaveToFile('C:\Temp\Screen.bmp');
          ms.Position := 0;
          Synchronize(
            procedure
            begin
              if FDesktopForm <> nil then
                FDesktopForm.imgScreen.Picture.Bitmap.LoadFromStream(ms);
            end
          );
          }

          fileSize := ReadIntegerFromSocket(SocketStrm);

          while (ms.Size < fileSize) and ClientSocket.Connected and (not Terminated) and (FDesktopForm <> nil) do
          begin
            Synchronize(
            procedure
              begin
                if FDesktopForm <> nil then
                  FDesktopForm.panInfo.Caption := 'Total: ' + IntToStr(ms.Size) + ' de ' + IntToStr(fileSize);
              end
            );

            nBytes := fileSize - ms.Size;
            if nBytes > Length(Buf) then nBytes := Length(Buf);

            ReadRawFromSocket(SocketStrm, buf[0], nBytes);
            ms.WriteBuffer(buf[0], nBytes);

            if ms.Size = fileSize then
            begin
              ms.Position := 0;
              ms.SaveToFile('C:\Temp\Screen.bmp');
              ms.Position := 0;
              Synchronize(
                procedure
                begin
                  if FDesktopForm <> nil then
                    FDesktopForm.imgScreen.Picture.Bitmap.LoadFromStream(ms);
                end
              );
            end;
          end;
        end;
      finally
        ms.Free;
      end;
    finally
      Synchronize(
        procedure
        begin
          if FDesktopForm <> nil then
            FDesktopForm.Close;
        end
      );
    end;
  finally
    SocketStrm.Free;
  end;
end;

end.

procedure TMainForm.ServerSocketGetThread(Sender: TObject;
  ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread);
begin
  SocketThread := TThreadController.Create(false, ClientSocket);
end;

客户端:

unit UntThreadMain;

interface

uses
  System.Classes,
  System.Win.ScktComp;

type
  TThreadMain = class(TThread)
  private
    FClientSocket: TClientSocket;
    FSocketStrm: TWinSocketStream;
    procedure SendInfo;
    procedure SendScreen;
    procedure OnConnect(Sender: TObject; Socket: TCustomWinSocket);
    procedure OnDisconnect(Sender: TObject; Socket: TCustomWinSocket);
    procedure OnError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer);
  protected
    procedure Execute; override;
  public
    constructor Create(AHostname: string; APort: integer); reintroduce;
    destructor Destroy; override;
  end;

implementation

uses
  System.SysUtils,
  WinApi.Windows,
  Vcl.Graphics,
  UntClientMainForm,
  UntSocketCommon;

{ TThreadMain }

constructor TThreadMain.Create(AHostname: string; APort: integer);
begin
  inherited Create(false);
  FreeOnTerminate := false;

  FClientSocket := TClientSocket.Create(nil);
  FClientSocket.ClientType := ctBlocking;
  FClientSocket.Host := AHostname;
  FClientSocket.Port := APort;
  FClientSocket.OnConnect := OnConnect;
  FClientSocket.OnDisconnect := OnDisconnect;
  FClientSocket.OnError := OnError;
end;

destructor TThreadMain.Destroy;
begin
  FClientSocket.Free;
  inherited;
end;

procedure TThreadMain.Execute;
var
  SocketStrm: TWinSocketStream;
  cmd: String;
begin
  FClientSocket.Open;
  try 
    FSocketStrm := TWinSocketStream.Create(FClientSocket.Socket, 5000);
    try
      while FClientSocket.Socket.Connected and (not Terminated) do
      begin
        if SocketStrm.WaitForData(1000) then
        begin
          cmd := ReadLineFromSocket(SocketStrm);
          if cmd = '<|INFO|>' then
          begin
            SendInfo
          end
          else if cmd = '<|GetScreen|>' then
          begin
            SendScreen;
          end
        end;
      end;
    finally
      FSocketStrm.Free;
    end;
  finally
    FClientSocket.Close;
  end;
end;

procedure TThreadMain.OnConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  Synchronize(
    procedure
    begin
      ClientMainForm.stBar.Panels[1].Text := 'Conectado';
      ClientMainForm.btnConectar.Caption := 'Desconectar';
    end
  );
end;

procedure TThreadMain.OnDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  Synchronize(
    procedure
    begin
      ClientMainForm.stBar.Panels[1].Text := 'Desconectado';
      ClientMainForm.btnConectar.Caption := 'Conectar';
    end
  );
end;

procedure TThreadMain.OnError(Sender: TObject; Socket: TCustomWinSocket;
  ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
  ErrorCode := 0;
  Socket.Close;
end;

procedure TThreadMain.SendInfo;
var
  cmd: string;
begin
  cmd := '<|INFO|>;NomePC=Tiago-PC;SO=Windows Seven Professiona 64-bit;CPU=Intel Core i7 3ª Geração';
  WriteLineToSocket(FSocketStrm, cmd);
end;

procedure TThreadMain.SendScreen;
var
  DC: HDC;
  bmp: TBitmap;
  ms: TMemoryStream;
begin
  ms := TMemoryStream.Create;
  try
    bmp := TBitmap.Create;
    try
      DC := GetDC(0);
      try
        //bmp.PixelFormat := pf8bit;
        bmp.Width := GetDeviceCaps(DC, HORZRES);
        bmp.Height := GetDeviceCaps(DC, VERTRES);
        //bmp.Width := Screen.Width;
        //bmp.Height := Screen.Height;
        BitBlt(bmp.Canvas.Handle, 0, 0, bmp.Width, bmp.Height, DC, 0, 0, SRCCOPY);
      finally
        ReleaseDC(0, DC);
      end;
      bmp.SaveToStream(ms);
    finally
      bmp.Free;
    end;
    ms.Position := 0;
    WriteStreamToSocket(FSocketStrm, ms);
  finally
    ms.Free;
  end;
end;

end.

procedure TClientMainForm.btnConectarClick(Sender: TObject);
begin
  if FThreadMain = nil then
  begin
    FThreadMain := TThreadMain.Create('localhost', 6550);
  end else
  begin
    FThreadMain.Terminate;
    FThreadMain.WaitFor;
    FThreadMain.Free;
    FThreadMain := nil;
  end;
end;