Full source code now available on GitHub. Covering Internet Direct (Indy), Ararat Synapse, and Synapse SynCrtSock.

This is the second part in a series which explores basic TCP socket use cases and presents them in minimal examples.

For this part, I selected an unusual string terminator byte sequence. The Unicode Character “☃” (U+2603), named Snowman, is not used in any protocol I am aware of. Encoded in UTF-8 it is three bytes long1. Some background: many Internet protocols use carriage return (octet 13) and/or line feed (octet 10) as line terminator. Therefore, some of the TCP socket libraries offer read methods with a configurable line terminator, but limited to these two. However, some (text-oriented) protocols use a different terminator. A notable example is STOMP, which specifies that the content must be terminated with a NULL byte2.

1) In UTF-8 encoding, Snowman is the byte sequence 0xE2 0x98 0x83.

2) See Stomp Protocol Specification Version 1.2.

Note: terminators with three or more bytes are supported by the provided code, but very unusual: every additional byte will slow down the request processing considerably.

The clients are tested with a small console application (see below).

program FixedDelimiterClient;

uses
  ClientIndySockets10,
  //ClientSynapse266,
  //ClientSynopseCrtSock,
  SysUtils;

const
  FIXED_DELIMITER = '' + #$2603; // Snowman
  // ☃
  SERVER_HOST = '127.0.0.1';
  SERVER_PORT = 30000;

  procedure Test(ADelimiter: string);
  var
    Response: string;
  begin
    WriteLn(Format('try to read from %s:%d delimited with %s',
      [SERVER_HOST, SERVER_PORT, ADelimiter]));
    Response := ReadDelimited(SERVER_HOST, SERVER_PORT, Utf8Encode(ADelimiter));
    WriteLn(Format('received response "%s" - %d bytes',
      [Response, Length(Response)]));
  end;

begin
  try
    Test(FIXED_DELIMITER);
    Test(FIXED_DELIMITER);
    Test(FIXED_DELIMITER);
  except
    on E: Exception do
    begin
      WriteLn(E.Message);
    end;
  end;
  ReadLn;
end. 

The Internet Direct (Indy) client source code:

function ReadDelimited(AHost: string; APort: Integer; ATerminator: RawByteString): string;
var
   Client: TIdTCPClient;
begin
   Client := TIdTCPClient.Create;
   try
     Client.Host := AHost;
     Client.Port := APort;
     Client.Connect;
     Result := Client.IOHandler.ReadLn(ATerminator, IndyTextEncoding_UTF8);
   finally
     Client.Free;
   end;
end;

Notes

Advertisement

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s