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;
- Included is a test server which responds with a snowman – delimited UTF-8 text ☃. The test server requires Indy for compilation.
- Credits: partially inspired by the thread https://en.delphipraxis.net/topic/7935-dl-a-file-from-the-web/
- Fork me on GitHub: https://github.com/michaelJustin/tcpclient-test