Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Porting old Delphi2007 application using TServerSocket....
#25
Just to close this thread with final thoughts if someone stumbles across it in the future...

It all seems to work now to use several different approaches, so I decided to use this where I have a TIdBytes buffer and read all available data every pass in the Execute procedure.
But I am using an event handler where the transfer container is a string, partial code below.

Note that I have both set the event handler Data container as const as shown below and without const. I see no difference either way.


Code:
type
  TCommRxEvent = procedure (Sender: TObject; const Data: string) of object;

  TTcpClientComm = class;

  { TReadingThread }

  TReadingThread = class(TThread)
  protected
    FRxData: TIdBytes;
    FOwner: TTcpClientComm;
  procedure Execute; override;
    procedure DoOnRxData;
  public
    constructor Create(Owner: TTcpClientComm);
  end;


  { TTcpClientComm }

  TTcpClientComm = class(TObject)
  private
    FConn: TIdTCPClient;
    FReadThread: TReadingThread;
    FOnRxData: TCommRxEvent;
    FOnLogMsgEvent: TLogMessageEvent;
    FLastError: string;
    FConnected: boolean;
    FHost: string;
    FPort: word;
    procedure OnStatusChange(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string);
    procedure LogEventData(Msg: Ansistring);
  public
    constructor Create;
    destructor  Destroy; override;
    property OnRxData: TCommRxEvent read FOnRxData write FOnRxData;
    property OnLogMsgEvent: TLogMessageEvent read FOnLogMsgEvent write FOnLogMsgEvent;
    property LastError: string read FLastError;
    property Connected: boolean read FConnected;
    property Host: string read FHost;
    property Port: word read FPort;
    procedure Connect(AHost: string; APort: word);
    procedure Disconnect;
    function  WriteData(const Data: string): boolean; overload;
    function  WriteData(const Data: TIdBytes): boolean; overload;
  end;

implementation
const
    ETX = #3;

constructor TTcpClientComm.Create;
begin
  FConnected := false;
  FHost := '';
  FPort := 0;
  FConn := TIdTCPClient.Create(NIL);
  FConn.OnStatus := OnStatusChange;
  FConn.ConnectTimeout := 5000; //5 second connect timeout
  FConn.ReadTimeout := 100; //Used in the read thread to not block
end;

procedure TTcpClientComm.Connect(AHost: string; APort: word);
begin
  try
    FLastError := '';
    FConn.Connect(AHost, APort); //Create read thread in OnStatus.hsConnected
    FHost := Host;
    FPort := APort;
  except
    on E: Exception do
    begin
      FLastError := E.Message;
    end;
  end;
end;

procedure TTcpClientComm.OnStatusChange(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string);
{This procedure parses the socket status change messages}
begin
  case AStatus of
    hsResolving: ;
    hsConnecting: ;
    hsConnected:
      begin
        FReadThread := TReadingThread.Create(Self);
        FConnected := true;
        LogEventData('Connected to server ' + FHost + ':' + IntToStr(FPort));
      end;
    hsDisconnecting: FConnected := false;
    hsDisconnected:
      begin
        FConnected := false;
        if FReadThread <> NIL then
          FReadThread.Terminate;
        if FReadThread <> NIL then
        begin
          FReadThread.WaitFor;
          FreeAndNil(FReadThread);
        end;
        LogEventData('Disconnected from server ' + FHost);
      end;
    hsStatusText:
      ;
  end;
end;

{ TReadingThread }

procedure TReadingThread.Execute;
begin
while not Terminated do
begin
    if FOwner.Connected then  //Do not use FConn.Connected here because that triggers a read operation on the socket...
    begin
      try
        FOwner.FConn.IOHandler.ReadBytes(FRxData, -1, False); //Get all available data
      except
        //Do nothing, timeout happened
      end;
      if (Length(FRxData) > 0) and Assigned(FOwner.FOnRxData) then
        Synchronize(DoOnRxData);
  end;
  end;
end;

procedure TReadingThread.DoOnRxData;
begin
  if Assigned(FOwner.FOnRxData) then
    FOwner.FOnRxData(Self, BytesToStringRaw(FRxData));
  SetLength(FRxData, 0);
end;

constructor TReadingThread.Create(Owner: TTcpClientComm);
begin
  FOwner := Owner;
  inherited Create(False);
end;
Reply


Messages In This Thread
RE: Porting old Delphi2007 application using TServerSocket.... - by BosseB - 10-01-2020, 08:02 PM

Forum Jump:


Users browsing this thread: 1 Guest(s)