1

It is always advised to perform all the sending / receiving tasks in OnExecute event handler of TIdTCPServer, but I do not understand following:

How to wait for a specific sequence on input and at the same time send some data to the same client? I need not a command-response sequence, but I need to:

  • send live data constantly
  • while receiving edited data back
  • and receiving commands and provide responses for them.

For example, if we are waiting for CR-LF:

procedure TSocketServer._serverExecute(AContext: TIdContext);
var
  msg: string;
begin
  msg := AContext.Connection.IOHandler.ReadLn();
  //Here we are only if CRLF was detected.
  //How to send while we are waiting?
  _log(msg);
end;
Paul
  • 25,812
  • 38
  • 124
  • 247
  • 1
    Open multiple connections. This requires multiple TCP components. – Jerry Dodge Apr 12 '19 at 15:04
  • On second thought, you could get away with only 1 TCP server, since it accepts connections from multiple clients. But on the client side, you'll need two, and some way of telling the server which is which. – Jerry Dodge Apr 12 '19 at 16:08
  • Set the timeout property of the IOHander so that the ReadLn function will continue after a time, even if no bytes are read. – Freddie Bell Apr 12 '19 at 17:43
  • 2
    Alternatively, before calling `IOHandler.ReadLn()`, call `IOHandler.CheckForDataOnSource()` with a timeout, and check with `IOHandler.InputBufferIsEmpty()` – Remy Lebeau Apr 12 '19 at 20:34
  • @JerryDodge "*But on the client side, you'll need two, and some way of telling the server which is which*" - you could have the server listen on 2 different ports. Then the client can open connections to both ports as needed. – Remy Lebeau Apr 12 '19 at 20:46
  • 1
    @Remy Indeed, there are numerous ways, I was offering one idea. But I was looking at it from a firewall point of view - the less ports to open, the easier. – Jerry Dodge Apr 12 '19 at 20:54

1 Answers1

5

It is important that when sending unsolicited data and response data using the same connection, don't overlap the outgoing messages, or else you will corrupt your protocol. It is best to have only 1 thread do all of the sending so that one message gets sent in full before another message is sent. Just make sure you design your protocol to allow unsolicited data to be sent after the client sends a command and before it receives a response. Each message should describe what kind of message it is, in such a way that the client can detect a response and match it to an earlier command, while handling unsolicited data as-is.

There is a few different ways you can handle the sending:

  • use separate threads for reading and sending. For instance, have the OnExecute thread handle all of the reading, and use another worker thread to handle all of the sending. If OnExecute receives an inbound command that needs to send a response, pass the response data to the sending thread (in a thread-safe manner) so it can send the response when safe to do so in between unsolicited messages.

  • have the OnExecute thread handle both reading and sending. Continuously send outgoing unsolicited data as needed, and periodically check for inbound data using the IOHandler.InputBufferIsEmpty() and IOHandler.CheckForSourceOnData() methods to detect when an inbound message needs to be read.

  • otherwise, like Jerry Dodge suggested in comments, just use separate connections, one for command-response data, and one for unsolicited data.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770