Search code examples
delphidelphi-xe2indyindy10

Using Indy Server's multiple bindings as separate sockets?


I'm still getting used to Indy, being a multi-threaded socket system with vast capabilities. One of the big things I've seen is how a server socket can have a number of different bindings. For example, you could have 3 bindings for 3 ports on the same IP address. I'm using Indy 10 on Delphi XE2.

I'm re-building an old system of mine which uses the old fashioned TServerSocket and TClientSocket components from ScktComps and re-doing it with Indy TIdTCPServer and TIdTCPClient. The old system actually consists of 3 completely different server/client sockets on each end, each socket serving a distinct purpose, and working together - similar to how FTP uses one socket for binary data and the other socket for commands.

Is it possible to mimic three separate server/client sockets within the same component using these bindings? It would be great if I can declare just one server socket with 3 ports bound, and same on the client, connected to 3 different ports on the server. All I would like to do is eliminate the need to create 3 separate server/client socket components and combine them into one.


Solution

  • Yes, you can use a single TIdTCPServer to manage multiple ports at a time. On the client side, you still need 3 distinct client components to connect to the different ports, though.

    Create 3 entries in the TIdTCPServer.Bindings collection, one for each local IP/Port that you want to listen on, where the TIdSocketHandle.Port property would be the equivilent of the TServerSocket.Port property. TServerSocket does not natively support binding to a specific IP (though it can be done with some manual work), but the TIdSocketHandle.IP property is used for that purpose, where a blank string is equivilent to INADDR_ANY.

    In the TIdCPServer.OnConnect, TIdCPServer.OnDisconnect, and TIdCPServer.OnExecute events, you can use the TIdContext.Binding.IP and TIdContext.Binding.Port properties to differentiate which binding the calling socket is connected to.

    A common use of this is to support SSL and non-SSL clients on different ports, such as for protocols like POP3 and SMTP which support implicit and explicit SSL/TLS on different ports. TIdHTTPServer does this for supporting HTTP and HTTPS urls on a single server (you can use the TIdHTTPServer.OnQuerySSLPort to customize which ports use SSL/TLS versus not).

    For example:

    procedure TForm1.StartButtonCick(Sender: TObject);
    begin
      IdTCPServer1.Active := False;
      IdTCPServer1.Bindings.Clear;
    
      with IdTCPServer1.Bindings.Add do
      begin
        IP := ...;
        Port := 2000;
      end;
    
      with IdTCPServer1.Bindings.Add do
      begin
        IP := ...;
        Port := 2001;
      end;
    
      with IdTCPServer1.Bindings.Add do
      begin
        IP := ...;
        Port := 2002;
      end;
    
      IdTCPServer1.Active := True;
    end;
    
    procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
    begin
      case AContext.Binding.Port of
        2000: begin
          // do something...
        end;
        2001: begin
          // do something else...
        end;
        2002: begin
          // do yet something else ...
        end;
      end;
    end;