07-06-2020, 08:03 PM
(07-05-2020, 01:08 PM)BosseB Wrote: So I have this old service application written in Delphi7 and maintained in Delphi2007 until about 2012.
Now it won't run anymore in Windows10
Why not? I have multiple services written in Delphi 6 (well, actually C++Builder 6, but it is the same VCL/RTL frameworks) and they work just fine on Windows 10.
(07-05-2020, 01:08 PM)BosseB Wrote: TIdTcpServer seems to be a natural replacement
Correct.
(07-05-2020, 01:08 PM)BosseB Wrote: Since Indy does not use events, how can I adapt this from TServerSocket to TidTcpServer?
The closest translation would look something like this:
Code:
sckServer: TIdTCPServer;
....
procedure sckServerConnect(AContext: TIdContext);
procedure sckServerDisconnect(AContext: TIdContext);
procedure sckServerExecute(AContext: TIdContext);
procedure sckServerException(AContext: TIdContext; AException: Exception);
...
procedure TSuperStingRemoteServer.sckServerConnect(AContext: TIdContext);
{Create the remote handler and assign the communication to it}
var
SSRC: TSSRemoteClientComm; //The communications object
i: integer;
PeerIP, PeerHost: string;
begin
try
FActivityTime := Now;
with sckServer.Contexts.LockList do
try
i := Count;
finally
sckServer.Contexts.UnlockList;
end;
// make sure Log3RServer is thread-safe, otherwise you need to sync access to it!
Log3RServer.StdLog('Active clients = ' + IntToStr(i));
if i > 1 then
begin
Log3RServer.StdLog('Only one active client allowed!');
AContext.Connection.Disconnect;
Exit;
end;
PeerIP := AContext.Binding.PeerIP;
PeerHost := GStack.HostByAddress(AContext.Binding.PeerIP, AContext.Binding.IPVersion);
Log3RServer.StdLog('SSRemote - Client connect, IP=' + PeerIP + ' Host=' + PeerHost);
AContext.Connection.IOHandler.DefStringEncoding := Indy8BitEncoding;
SSRC := TSSRemoteClientComm.Create(AContext, FRemoteServer);
AContext.Data := SSRC; {Keep pointer to handler with socket}
SSRC.Log := Log3RComm;
FRemoteServer.ClientCallback := SSRC.ClientCallback;
Log3RServer.StdLog('SSRemote - initializing new SSRemote Client');
SSRC.Initialize;
SSRC.Log.StdLog('Socket communication channel opened to ' + PeerIP + ' Host=' + PeerHost);
except
on E: Exception do
begin
Log3RServer.ErrLog('Exception during client connect: ' + E.Message);
AContext.Connection.Disconnect;
Exit;
end;
end;
end;
procedure TSuperStingRemoteServer.sckServerDisconnect(AContext: TIdContext);
begin
FRemoteServer.ClientCallback := nil;
LogStd('Client disconnect ' + AContext.Binding.PeerIP);
FActivityTime := Now;
if AContext.Data <> nil then
begin
TSSRemoteClientComm(AContext.Data).OnDisconnect(AContext);
TSSRemoteClientComm(AContext.Data).Free;
AContext.Data := nil;
end;
end;
procedure TSuperStingRemoteServer.sckServerExecute(AContext: TIdContext);
var
RdData: string;
begin
{Implement the socket data flow here by using the Data pointer to the handling object}
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
AContext.Connection.IOHandler.CheckForDataOnSource(500);
AContext.Connection.IOHandler.CheckForDisconnect;
if AContext.Connection.IOHandler.InputBufferIsEmpty then Exit;
end;
RdData := AContext.Connection.IOHandler.InputBufferAsString;
FActivityTime := Now;
if AContext.Data <> nil then
TSSRemoteClientComm(AContext.Data).OnDataRead(RdData);
end;
procedure TSuperStingRemoteServer.sckServerException(AContext: TIdContext; AException: Exception);
begin
{Implement the socket error handling here}
if not (AException is EIdConnClosedGracefully) then
LogErr('Socket error detected: ' + AException.Message);
end;
(07-06-2020, 02:29 PM)BosseB Wrote: What I would like to know is if the TIdTCPServer object will trigger the OnExecute event when data arrive from the connected client?
Not when new data arrives, no. The OnExecute event handler is called in a continuous loop for the lifetime of the socket connection, regardless of the data. The handler is expected to do its own waiting for new data as needed, such as by using blocking socket I/O operations.
(07-06-2020, 02:29 PM)BosseB Wrote: The example I cut code from uses OnExecute to retrieve and process client data, but I seem not to get any extraction here...
<snip>
The test client I have will send a login message following connection and it looks like this:
<STX>USER=username<CR>PWD=password<ETX>
So it is delimited using <STX> and <ETX> and the payload between these can be any normal ASCII characters incluting <CR>, <LF>, <TAB> etc.
<snip>
So how can I get the content of the delimited message from the client in OnExecute?
You can call ReadLn() with a custom terminator. The default is LF (which also handles CRLF), but you can use any terminator you want, like ETX, eg:
Code:
procedure TRemoteServer.ServerExecute(AContext: TIdContext);
var
msg, reply: string;
begin
AContext.Connection.IOHandler.WaitFor(#2, True, False); // <-- optional
msg := AContext.Connection.IOHandler.ReadLn(#3);
reply := ProcessRequest(msg);
AContext.Connection.IOHandler.Write(#2 + reply + #3);
end;