Indy TCP Client/Server with the client acting as a server

jpfollenius picture jpfollenius · Dec 7, 2011 · Viewed 39.6k times · Source

How can Indy's TIdTCPClient and TIdTCPServer be used in the following scenario:

Client  ---------- initate connection -----------> Server
...
Client  <---------------command------------------- Server
Client  ----------------response-----------------> Server
...
Client  <---------------command------------------- Server
Client  ----------------response-----------------> Server

The client initiates the connection, but acts as a "server" (waiting for commands and executing them).

The OnExecute approach of TIdTCPServer does not work well in this case (at least I am not getting it to work well). How could I do this?

I hope the question is clear enough.

Answer

Marcus Adams picture Marcus Adams · Dec 7, 2011

There is nothing preventing you from doing this with Indy's TIdTCPServer component.

A TIdTCPServer only sets up the connection. You'll need to implement the rest. So the sequence of the actual sending and receiving can be whatever you want.

Put this code in your TIdTCPServer component's OnExecute event:

var
  sName: String;
begin
  // Send command to client immediately after connection
  AContext.Connection.Socket.WriteLn('What is your name?');
  // Receive response from client
  sName := AContext.Connection.Socket.ReadLn;
  // Send a response to the client
  AContext.Connection.Socket.WriteLn('Hello, ' + sName + '.');
  AContext.Connection.Socket.WriteLn('Would you like to play a game?');
  // We're done with our session
  AContext.Connection.Disconnect;
end;

Here's how you can setup the TIdTCPServer really simply:

IdTCPServer1.Bindings.Clear;
IdTCPServer1.Bindings.Add.SetBinding('127.0.0.1', 8080);
IdTCPServer1.Active := True;

This tells the server to listen on the loopback address only, at port 8080. This prevents anyone outside of your computer from connecting to it.

Then, to connect your client, you can go to a Windows command prompt and type the following:

telnet 127.0.0.1 8080

Here's the output:

What is your name?

Marcus

Hello, Marcus.

Would you like to play a game?

Connection to host lost.

Don't have telnet? Here's how to install telnet client on Vista and 7.

Or with a TIdTCP Client, you can do this:

var
  sPrompt: String;
  sResponse: String;
begin
  // Set port to connect to
  IdTCPClient1.Port := 8080;
  // Set host to connect to
  IdTCPClient1.Host := '127.0.0.1';
  // Now actually connect
  IdTCPClient1.Connect;
  // Read the prompt text from the server
  sPrompt := IdTCPClient1.Socket.ReadLn;
  // Show it to the user and ask the user to respond
  sResponse := InputBox('Prompt', sPrompt, '');
  // Send user's response back to server
  IdTCPClient1.Socket.WriteLn(sResponse);
  // Show the user the server's final message
  ShowMessage(IdTCPClient1.Socket.AllData);
end;

An important thing to note here is that the ReadLn statements wait until there is data. That's the magic behind it all.