Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Porting old Delphi2007 application using TServerSocket....
#15
(07-07-2020, 10:33 AM)BosseB Wrote: I have tried to use an event function that contains the data but then I got an error from Lazarus.

That is because you are not using TThread.Synchronize() correctly.  It needs to look like this instead:

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

  { TReadingThread }

  TReadingThread = class(TThread)
  protected
    FConn: TIdTCPConnection;
    FOnRxData: TCommRxEvent;
    FRxData: string;
    procedure Execute; override;
    procedure DoOnRxData;
  public
    constructor Create(ACon: TIdTCPConnection);
    property OnRxData: TCommRxEvent read FOnRxData write FOnRxData;
  end;

...
procedure TReadingThread.Execute;
begin
  while not Terminated do
  begin
    if FConn.Connected then
    begin
      if FConn.IOHandler.CheckForDataOnSource(10) then
      begin
        if FConn.IOHandler.InputBuffer.Size > 0 then
        begin
          // read bytes from FConn up to InputBuffer.Size bytes ...
          FRxData := FConn.IOHandler.ReadString(FConn.IOHandler.InputBuffer.Size);
          //
          // process bytes as needed ...
          if Assigned(FOnRxData) then
            Synchronize(DoOnRxData);
        end;
      end;
    end;
  end;
end;

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

In Delphi ,you could do the following instead, but FreePasscal does not support this approach yet:

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

  { TReadingThread }

  TReadingThread = class(TThread)
  protected
    FConn: TIdTCPConnection;
    FOnRxData: TCommRxEvent;
    FRxData: string;
    procedure Execute; override;
  public
    constructor Create(ACon: TIdTCPConnection);
    property OnRxData: TCommRxEvent read FOnRxData write FOnRxData;
  end;

...
procedure TReadingThread.Execute;
begin
  while not Terminated do
  begin
    if FConn.Connected then
    begin
      if FConn.IOHandler.CheckForDataOnSource(10) then
      begin
        if FConn.IOHandler.InputBuffer.Size > 0 then
        begin
          // read bytes from FConn up to InputBuffer.Size bytes ...
          FRxData := FConn.IOHandler.ReadString(FConn.IOHandler.InputBuffer.Size);
          //
          // process bytes as needed ...
          if Assigned(FOnRxData) then
          begin
            Synchronize(
              procedure
              begin
                if Assigned(FOnRxData) then
                  FOnRxData(Self, FRxData);
              end
            );
          end;
        end;
      end;
    end;
  end;
end;

(07-07-2020, 10:33 AM)BosseB Wrote:
Quote:I will say, though, that you should not create the reading thread until after the TIdTCPClient has been connected first.  And then terminate and free the thread when the TIdTCPClient is being disconnected.

How can I do that, i.e. how do I know the connect and disconnect happened?

You are the one calling Connect() and Disconnect().  So, simply don't create the thread until you have called Connect() and it has exited without raising an exception.  Terminate() the thread before calling Disconnect(), and then finish freeing the thread after Disconnect() exits.

(07-07-2020, 10:33 AM)BosseB Wrote: Do you mean passing the data out in the event handler in a TIdBytes container?

Yes.

(07-07-2020, 10:33 AM)BosseB Wrote: Or should the event not contain the data and the reading be done by the handler itself?

No, the reading should be done before the event handler is called.  Let the thread do its job.  HOW the thread reads, and WHAT it passes to the event, depend on your particular needs.  For instance, given the STX/ETX example you provided earlier, the thread could wait for STX to arrive, then read until ETX arrives, and then pass everything in between to the event.

(07-07-2020, 10:33 AM)BosseB Wrote: I.e. the event is just a Synchronized notification and the socket read is done in the event implementation instead?

No.

(07-07-2020, 10:33 AM)BosseB Wrote: Seems like it would be better keep that from the caller and just provide the received data itself, that is at least what I thought a better encapsulation.

Yes.

Reply


Messages In This Thread
RE: Porting old Delphi2007 application using TServerSocket.... - by rlebeau - 08-31-2020, 07:23 PM

Forum Jump:


Users browsing this thread: 2 Guest(s)