08-28-2020, 08:53 PM
I managed to get the server working with your help! Thanks for that!
Now I have a new task and this is to port the client application to FreePascal/Lazarus from Delphi.
Again I need to replace an old socket component with an Indy10 implementation, i.e. I need to create a receive event for TIdTcpClient...
In this case I have found a number of examples which for some reason do not work (Lazarus complains) which use a thread to read incoming data and then use an event function to feed the main application.
So I decided to make a class that handles this with Indy10 and implements the functions used by the earlier solution.
This uses a read thread as described in several old forum posts...
Below is how far I have come but I have gotten stuck concerning how to best retrieve the data in the thread Execute and supply it to the client via the event procedure.
Questions:
What should I put into the thread execute function on data reception to transfer it into the event?
Should I read the data in the thread or should I just push a notification that data are available and let the implementation of the event procedure read from the socket?
Here is my current (incomplete) state of the code:
Now I have a new task and this is to port the client application to FreePascal/Lazarus from Delphi.
Again I need to replace an old socket component with an Indy10 implementation, i.e. I need to create a receive event for TIdTcpClient...
In this case I have found a number of examples which for some reason do not work (Lazarus complains) which use a thread to read incoming data and then use an event function to feed the main application.
So I decided to make a class that handles this with Indy10 and implements the functions used by the earlier solution.
This uses a read thread as described in several old forum posts...
Below is how far I have come but I have gotten stuck concerning how to best retrieve the data in the thread Execute and supply it to the client via the event procedure.
Questions:
What should I put into the thread execute function on data reception to transfer it into the event?
Should I read the data in the thread or should I just push a notification that data are available and let the implementation of the event procedure read from the socket?
Here is my current (incomplete) state of the code:
Code:
unit TcpClientComm;
{******************************************************************************
* This is an attempt to use Indy10 TIdTcpClient object as a TCP/IP connection
* while providing an event driven model for receiving data from the server.
*
*
*******************************************************************************}
{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
interface
uses
Classes,
SysUtils,
IdBaseComponent,
IdComponent,
IdTCPConnection,
IdTCPClient,
IdGlobal
;
type
TCommRxEvent = procedure (Sender: TObject; Data: string) of object;
{ TReadingThread }
TReadingThread = class(TThread)
protected
FConn: TIdTCPConnection;
FOnRxData: TCommRxEvent;
procedure Execute; override;
public
constructor Create(ACon: TIdTCPConnection);
property OnRxData: TCommRxEvent read FOnRxData write FOnRxData;
end;
{ TTcpClientComm }
TTcpClientComm = class(TObject)
private
FConn: TIdTCPClient;
FReadThread: TReadingThread;
FOnRxData: TCommRxEvent;
FLastError: string;
function GetConnected: boolean;
public
constructor Create;
destructor Destroy; override;
property OnRxData: TCommRxEvent read FOnRxData write FOnRxData;
property LastError: string read FLastError;
property Connected: boolean read GetConnected;
procedure Connect(Host: string; Port: word);
procedure Disconnect;
function WriteString(Data: string): boolean; overload;
function WriteData(Data: TIdBytes): boolean; overload;
end;
implementation
{ TTcpClientComm }
function TTcpClientComm.GetConnected: boolean;
begin
Result := FConn.Connected;
end;
constructor TTcpClientComm.Create;
begin
FConn := TIdTCPClient.Create(NIL);
FReadThread := TReadingThread.Create(FConn);
end;
destructor TTcpClientComm.Destroy;
begin
inherited Destroy;
end;
procedure TTcpClientComm.Connect(Host: string; Port: word);
begin
FConn.Connect(Host, Port);
end;
procedure TTcpClientComm.Disconnect;
begin
FConn.Disconnect;
end;
function TTcpClientComm.WriteString(Data: string): boolean;
var
DataBytes: TIdBytes;
begin
Result := false;
FLastError := 'No data';
if Length(Data) = 0 then exit;
SetLength(DataBytes, Length(Data));
Move(Data[1], DataBytes[0], Length(Data));
Result := WriteData(DataBytes);
end;
function TTcpClientComm.WriteData(Data: TIdBytes): boolean;
begin
Result := false;
FLastError := 'No data';
if Length(Data) = 0 then exit;
if not FConn.Connected then
begin
FLastError := 'Not connected';
exit;
end;
try
FConn.IOHandler.Write(Data);
Result := true;
except
on E: Exception do
FLastError := E.Message;
end;
end;
{ TReadingThread }
procedure TReadingThread.Execute;
begin
while not Terminated do
begin
if FConn.IOHandler.CheckForDataOnSource(10) then
if FConn.IOHandler.InputBuffer.Size > 0 then
begin
// read bytes from FConn up
// to InputBuffer.Size bytes ...
//
// process bytes as needed ...
end;
end;
end;
constructor TReadingThread.Create(ACon: TIdTCPConnection);
begin
FConn := ACon;
inherited Create(False);
end;