Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Porting old Delphi2007 application using TServerSocket....
#3
(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;

Reply


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

Forum Jump:


Users browsing this thread: 1 Guest(s)