![]() |
Beispielcode für TCP Socket Client Bibliotheken (Delphi & Free Pascal)
Für meine Delphi- und Free Pascal Projekte verwende ich diverse TCP Bibliotheken.
Diese unterscheiden sich in ihrer API, manche sind eher high-level orientiert, andere nur ein kleiner Wrapper für die Windows API. Das macht einen Wechsel, oder bibliotheksunabhängige Programmierung (bei der mehrere Bibliotheken unterstützt werden) nicht leicht. Dadurch motiviert, sammele ich auf GitHub nun Codebeispiele für typische, einfache, Aufgabenstellungen. Die Repository-Adresse ist ![]() Teil 1: Lesen einer festen Anzahl von Bytes Im ersten Teil des Projekts geht es um das Lesen einer festen Anzahl von Bytes vom Server. Dazu gibt es einen TCP Server, der dem Client eine feste Anzahl bytes zurückgibt und dann die Verbindung trennt. Client-Testanwendungen für diese Bibliotheken sind enthalten: * Indy 10 - ![]() * Ararat Synapse - ![]() * Synopse - ![]() Alle Client-Beispiele enthalten nur eine Methode:
Delphi-Quellcode:
Diese wird von der Test-Methode aufgerufen, und die zurückggebene Länge ermittelt und ausgegeben.
function Read(AHost: string; APort: Integer; ALength: Integer): TBytes;
Für Indy sieht das Beispiel folgendermassen aus:
Delphi-Quellcode:
Für jede Bibliothek muss nur die entsprechende Unit verwendet werden, und die anderen auskommentiert:
program FixedLengthClient;
uses ClientMainIndy10, SysUtils; const CONTENT_LENGTH = 8192; SERVER_HOST = '127.0.0.1'; SERVER_PORT = 30000; procedure Test(AExpectedLength: Integer); var Response: TBytes; begin WriteLn(Format('try to read %d bytes from %s:%d', [AExpectedLength, SERVER_HOST, SERVER_PORT])); Response := Read(SERVER_HOST, SERVER_PORT, AExpectedLength); WriteLn(Format('received %d bytes', [Length(Response)])); end; begin try Test(CONTENT_LENGTH); Test(CONTENT_LENGTH - 1); Test(CONTENT_LENGTH + 1); // (surprise me) except on E: Exception do begin WriteLn(E.Message); end; end; ReadLn; end.
Delphi-Quellcode:
Die Projekte sind zwar mit Free Pascal / Lazarus erstellt, sollten aber mit Delphi 2009 und neuer kompatibel sein. (Delphi dpr Dateien können durch Umbenennen der lpr erzeugt werden)
uses
//ClientMainIndy10, //ClientSynapse266, ClientSynopseCrtSock, SysUtils; |
AW: Beispielcode für TCP Client Bibliotheken (Delphi & Free Pascal)
Tatsächlich habe ich beruflich gerade ein ähnliches Thema bearbeitet (HTTP und Rest statt TCP). Ich habe eine Wrapperklasse erstellt, der man einfach sagen kann, welches Framework sie zur Kommunikation nutzen soll und ob die Kommunikation asynchron erfolgen soll. Diese asynchrone Kommunikation finde ich, gerade bei solchen Beispielen, sehr wichtig, denn diese ist noch schwieriger unter einen Hut zu bekommen.
Statt mehrere einzelne Beispiele zu schreiben, wäre vielleicht eine Überlegung, auch hier einen Wrapper zu schreiben, den man dann frameworkunabhängig nutzen kann. Ich würde in die Liste der Framworks noch ICS aufnehmen. Das gefällt mir sehr gut, unter anderem weil z.B. bei (ja, anderes Thema) SSL-Verbindungen sehr ausführliche und hilfreiche Logs geschrieben werden können und auch die (im Gegensatz zu Indy) non-blocking sockets finde ich sehr nützlich. |
AW: Beispielcode für TCP Socket Client Bibliotheken (Delphi & Free Pascal)
Zitat:
![]() Bis bald... Thomas |
AW: Beispielcode für TCP Socket Client Bibliotheken (Delphi & Free Pascal)
Das ist irgendwie eine ähnliche Diskussion wie "Was ist besser: Windows oder [xyz]?" Letztlich muss man sich selbst fragen: Wie wichtig ist einem das Thema Netzwerkkommunikation im eigenen Projekt? Wie viel Arbeit will ich investieren? Soll das Projekt plattformunabhängig sein? Vertraue ich einem bestimmten Hersteller und/oder proprietären OS?
Ich persönlich nutze Indy, weil es plattformunabhängig ist und ziemlich Low-Level ansetzt um den gesamten Protokollstack selbst abzubilden. Leider ist die Entwicklung in den letzten Jahren ins Stocken geraten, vor allem weil Remy kaum noch Zeit dafür hat. So ist z.B. OpenSSL 1.1 immer noch nicht final im Hauptzweig integriert. Dabei war OpenSSL genau der Grund, weshalb ich mich damals nicht auf die Emba-Lösung eingelassen habe, denn die setzt unter Windows auf WinInet und da ist man bei SSL/TLS-Verbindungen auf Gedeih und Verderb deren Zertifikatspeicher ausgeliefert - und den hat Microsoft schon mehrfach per Windowsupdate sabotiert. Bisher bin ich mit Indy sehr gut gefahren, noch gibt es keine TLS-1.3-only-Server in meinem Ökosystem, aber irgendwann wirds passieren und dann wären wir mit Indy und OpenSSL 1.0.x angeschmiert. |
AW: Beispielcode für TCP Socket Client Bibliotheken (Delphi & Free Pascal)
Zitat:
Da neuere Verschlüsselungen oder Kurven nicht unbedingt von allen Frameworks unterstützt werden, ist es gut, wenn man das Framework bei Bedarf relativ einfach wechseln kann. |
AW: Beispielcode für TCP Socket Client Bibliotheken (Delphi & Free Pascal)
Zitat:
![]() Die Browser bringen diese Prüfinfrastruktur selbst mit, Microsoft liefert aber mit WinInet auch eine API zu einer solchen Infrastruktur. Die meinte ich, die hat Windows Update schon mehrfach kaputt gepatched. Aus Anwendungssicht ist der Effekt dann der selbe: Du bekommst keine verschlüsselte Verbindung aufgebaut. Also neben der gewollten Sollbruchstelle noch eine ungewollte. |
AW: Beispielcode für TCP Socket Client Bibliotheken (Delphi & Free Pascal)
Danke für das Feedback und die Anregungen! Ich freue mich natürlich auch über Pull Requests auf das GitHub Repository mit Vorschlägen, alternativ gerne per PM etc.
Nun ist der zweite Teil erschienen: Teil 2: Lesen eines Snowman ☃ - terminierten Strings von einem TCP Socket Dazu gibt es auch wieder einen ![]() Der Server sendet in diesem Beispiel einen kurzen Text an den Client, gefolgt von der Byte-Sequenz $2603, dies ist der Unicode-Wert für das Snowman Symbol. Die clientseitige Implementierung für Indy und Synapse ist relativ kompakt und leicht lesbar. Hier die für Synapse:
Delphi-Quellcode:
Der Terminator wird dazu im Beispiel als Konstante definiert:
function ReadDelimited(AHost: string; APort: Integer; ATerminator: RawByteString): string;
var FSock: TTCPBlockSocket; begin FSock := TTCPBlockSocket.Create; try FSock.RaiseExcept := True; FSock.Connect(AHost, IntToStr(APort)); Result := FSock.RecvTerminated(1000, ATerminator); finally FSock.Free; end; end;
Delphi-Quellcode:
Das Testprogramm sieht aktuell so aus:
FIXED_DELIMITER = '' + #$2603; // '☃';
Delphi-Quellcode:
Da es eine Konsolenanwendung ist, sieht man den Snowman leider nicht.
program FixedDelimiterClient;
uses ClientIndySockets10, //ClientSynapse266, //ClientSynopseCrtSock, SysUtils; const FIXED_DELIMITER = '' + #$2603; // '☃'; 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. Es erscheint nur "try to read from 127.0.0.1:30000 delimited with ?' |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:44 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz