Search code examples
c++c++builderindyindy10

Use TIdCmdTCPServer for binary data?


I have a TCP server in my Windows application based on TIdCmdTCPServer and it has been performing great. Now I have a device that does not send text string but binary data. I really don't want to rewrite my working code to use TIdTCPServer.

Is there any way I can use my current code and grab the discarded data somewhere, i.e. can I have access to the raw data received without interfering with other connections that use text?

I tried the OnBeforeCommandHandler event, but it already seems to assume the data is a string (i.e. cuts off at the first zero byte).


Solution

  • TIdCmdTCPServer does not stop reading on nul bytes, like you claim. By default, it reads each command by calling TIdIOHandler.ReadLn(), which reads until a (CR+)LF is received. However, the TIdIOHandler.DefStringEncoding is set to US-ASCII by default, so that could be causing data loss when reading binary data as a string.

    That being said, TIdCmdTCPServer is designed primarily for textual commands. By default, tt cannot receive binary commands, or binary parameters. However, if the binary data follows a textual command, your TIdCommandHandler.OnCommand event handlers can read the binary data after the command has been received, by simply reading the binary using the ASender.Context.Connection.IOHandler as needed.

    Otherwise, if that does not suit your needs (because the binary commands are not in a format that would normally trigger an OnCommand event), you will have to derive a new class from TIdCmdTCPServer and have it either:

    • override the virtual ReadCommandLine() method to read a binary command and its parameters from the Connection and return that data in a string format of your choosing (you can use Indy's IndyTextEncoding_8bit encoding, or BytesToStringRaw() function, to help you with that, or use whatever string format you want). And then define a CommandHandler to match that stringified command.

    • override the virtual DoExecute() method, then you have full control over the reading of the Connection and can handle commands however you want. To trigger OnCommand events, call the server's CommandHandlers.HandleCommand() method passing it string values of your choosing.

    Personally, I would not recommend mixing textual and non-textual clients on the same server. They are clearly using different protocols, so you should be using different servers on different ports to handle them separately.