Using Indy Server's multiple bindings as separate sockets?

Jerry Dodge picture Jerry Dodge · Jun 7, 2012 · Viewed 7.3k times · Source

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.

Answer

Remy Lebeau picture Remy Lebeau · Jun 8, 2012

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;