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