Search code examples
socketsdelphiindyindy10

Is there an Indy server property equivalent to TCustomWinSocket.Data?


When I work with TServerSocket I can use the property Data to store a pointer to a class for example for each client.

Now I will use Indy TIdCmdTCPServer and I'd like to know if there is an equivalent property.


Solution

  • Yes, there is - the TIdContext.Data property. In TIdCmdTCPServer events that give you a TIdCommand parameter instead of a TIdContext parameter, you can access the TIdContext object from the TIdCommand.Context property. For example:

    type
      TMyClass = class
        // add whatever you need...
      end;
    
    procedure TForm1.IdCmdTCPServer1Connect(AContext: TIdContext);
    var
      MyCls: TMyClass;
    begin
      MyCls := TMyClass.Create;
      // initialize MyCls as needed...
      AContext.Data := MyCls;
    end;
    
    procedure TForm1.IdCmdTCPServer1Disconnect(AContext: TIdContext);
    begin
      AContext.Data.Free;
      AContext.Data := nil;
    end;
    
    procedure TForm1.IdCmdTCPServer1CommandHandlerCommand(ACommand: TIdCommand);
    var
      MyCls: TMyClass;
    begin
      MyCls := TMyClass(ACommand.Context.Data);
      // use MyCls as needed...
    end;
    

    Indy also has another useful feature. You can derive a custom class from TIdServerContext, add whatever you want to it, and then assign it to the server's ContextClass property before activating the server. That way, you can simply typecast any TIdContext pointer to your class type when you need to access your custom members. For example:

    type
      TMyContext = class(TIdServerContext)
      public
        // add whatever you need...
        constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil); override;
        destructor Destroy; override;
      end;
    
    constructor TMyContext.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil);
    begin
      inherited;
      //...
    end;
    
    destructor TMyContext.Destroy;
    begin
      //...
      inherited;
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      IdCmdTCPServer1.ContextsClass := TMyContext;
    end;
    
    procedure TForm1.IdCmdTCPServer1Connect(AContext: TIdContext);
    var
      MyCtx: TMyContext;
    begin
      MyCtx := TMyClass(AContext);
      // initialize MyCtx as needed...
    end;
    
    procedure TForm1.IdCmdTCPServer1CommandHandlerCommand(ACommand: TIdCommand);
    var
      MyCtx: TMyContext;
    begin
      MyCtx := TMyClass(ACommand.Context);
      // use MyCtx as needed...
    end;
    

    This way, you don't need to waste time and memory allocating a separate class per client, when you can use the one that the server already creates for you.