Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Porting old Delphi2007 application using TServerSocket....
#21
I have started debugging tests now with the Linux port of the server and the client running on Windows but ported to FPC/Lazarus.
On the client side I use the newly created TTcpClientComm object based on TIdTcpClient and I have discovered some issues when dealing with larger amounts of data...
Here is the declaration of the object plus the thread implementation:

Code:
  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;

{ 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
      FOwner.FConn.IOHandler.ReadBytes(FRxData, -1, False); //Get all available data
      if Assigned(FOwner.FOnRxData) then
        Synchronize(DoOnRxData);
      end;
  end;
end;

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

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

As you can see I am setting the FRxData container to zero length after it has been submitted to the event handler.
I did this to ensure that the received data are not processed twice.
In the client the event procedure looks like this:

Code:
procedure TSSRemoteClient.OnRxData(Sender: TObject; const Data: TIdBytes);
{This event is where data from the TCP/IP connection to the server are received.
Move data into a string and process as needed.}
var
  RxData: string;
  len: integer;
begin
  len := Length(Data);
  SetLength(RxData, len);
  Move(Data[0], RxData[1], len);
  HandleRxCommand(RxData);
end;
The reason the data is moved into a string is that the bulk of the existing processing (which has worked OK for many years) is using the string type as a container for the data. And in this case all payload data are textual even transfered files because they are hex encoded before transfer (doubles the byte count but makes it possible to deal with as text)

Now it seems like I am losing some received data when the amount is large like when the content of a logfile is transferred.

Is this possibly the reason?
How can I safeguard against data loss?
During synchronize, I thought that the read thread is paused until the event procedure returns, is that correct?

I can compare the operations of this new ported client with the old Delphi client and I see the problems this way.
Reply


Messages In This Thread
RE: Porting old Delphi2007 application using TServerSocket.... - by BosseB - 09-29-2020, 11:20 AM

Forum Jump:


Users browsing this thread: 2 Guest(s)