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
- 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