sgcWebSockets 2026.7: Clustering, Nachrichtenhistorie, async / await und gehärtete Clients | eSeGeCe Blog

sgcWebSockets 2026.7: Clustering, Nachrichtenhistorie, async / await und gehärtete Clients

· Versionen

Bei sgcWebSockets 2026.7 geht es um den Produktivbetrieb. Sie können eine WebSocket-Anwendung jetzt über mehrere Server verteilen und dabei Kanäle, Pub/Sub und Präsenz über alle hinweg funktionsfähig halten. Kanäle können sich ihre jüngsten Nachrichten merken, sodass ein Client, der die Verbindung verliert und zurückkommt, alles Verpasste erhält. Clients verbinden sich mit exponentiellem Backoff und Jitter neu, statt im Gleichschritt auf den Server einzuhämmern, die Sendewarteschlange kann begrenzt werden, damit ein langsamer Konsument den Serverspeicher nicht erschöpft, und der HTTP Client hat einen Satz Schutzmechanismen gegen Weiterleitungen erhalten, die Zugangsdaten preisgeben, gegen herabgestuftes TLS und gegen Antworten ohne Größenbegrenzung.

Dazu kommen eine async / await-Schicht für Delphi, gzip und deflate auf den HTTP Servern, die neue HTTP QUERY Methode, Identitätsprüfung für die Ende-zu-Ende-Verschlüsselung, OAuth2 im MCP Client und eine lange Liste von Fehlerbehebungen. Dieser Beitrag ist die geführte Tour. Jeder Abschnitt verweist auf den Artikel, der die Funktion ausführlich behandelt.

Clustering über mehrere Server

Die neue Komponente TsgcWSCluster verbindet mehrere sgcWebSockets Server zu einem logischen Server. Eine auf Knoten A veröffentlichte Nachricht erreicht Abonnenten, die mit Knoten B verbunden sind, und die Präsenz liefert die Teilnehmerliste des gesamten Clusters statt nur des lokalen Knotens. Zwei Backplanes stehen zur Verfügung: ein eingebautes Mesh, bei dem die Knoten direkt miteinander sprechen und Sie nichts zusätzlich installieren, und Redis Pub/Sub für größere Installationen (Enterprise).

uses
  sgcWebSocket, sgcWebSocket_Protocols, sgcWebSocket_Cluster;

oCluster := TsgcWSCluster.Create(nil);
oCluster.EngineType  := clusterMesh;          // no extra infrastructure
oCluster.ClusterPort := 5410;                 // this node's mesh listener
oCluster.Peers.Add('192.168.1.101:5410');     // the other nodes
oCluster.Attach(oProtocol);                   // cluster this protocol's pub/sub
oCluster.Start;

Mehr dazu: WebSocket Server über mehrere Knoten skalieren.

Nachrichtenhistorie und Wiederherstellung nach einer Neuverbindung

Der sgc-Protokollserver kann jetzt die letzten N Nachrichten jedes Kanals aufbewahren, optional mit einer Lebensdauer. Wenn ein Client sich neu verbindet und erneut abonniert, sendet er den Offset der letzten Nachricht, die er tatsächlich gesehen hat, und der Server spielt alles nach, was während seiner Abwesenheit veröffentlicht wurde. In Ihrem Client-Code ändert sich nichts über das erneute Abonnieren hinaus, das Sie ohnehin schon tun, und das Ganze ist aus, solange Sie es nicht aktivieren.

oProtocol.History.Enabled    := True;
oProtocol.History.Size       := 1000;   // last 1000 messages per channel
oProtocol.History.TTLSeconds := 3600;   // optional: also expire after 1 hour

Mehr dazu: Nachrichtenhistorie und Wiederherstellung nach einer Neuverbindung.

async / await, und ein Connect, das wirklich wartet

Die neue Unit sgcBase_AsyncAwait bringt Tasks und Futures in die Bibliothek. Sie können auf eine HTTP-Anfrage, eine WebSocket-Verbindung oder eine AI Chat Completion warten, ohne einen einzigen Ereignis-Handler zu verdrahten, das Ergebnis mit ThenProc und OnError verketten und einen Task so abbrechen, dass die zugrunde liegende Anfrage tatsächlich abgebrochen wird.

Im selben Sinne blockiert Connect jetzt, bis die Verbindung vollständig aufgebaut und nicht bloß begonnen ist, und Disconnect wartet, bis der Socket wirklich geschlossen ist. Damit ist ein Wettlauf geschlossen, der bei schnellen Neuverbindungen zubeißen konnte. Wenn ein Verbindungsaufbau oder ein Senden fehlschlägt, steht der Grund in der neuen Eigenschaft LastError, und es gibt eine Connect-Überladung, die Ihnen den Fehlertext direkt zurückgibt, sodass Sie einen Fehlschlag diagnostizieren können, ohne OnError zu abonnieren.

var
  vError: string;
begin
  if sgcWebSocketClient1.Connect(10000) then
    sgcWebSocketClient1.WriteData('hello')
  else
    ShowMessage('Connect failed: ' + sgcWebSocketClient1.LastError);

  // or get the reason back directly from the call
  if not sgcWebSocketClient1.Connect(vError, 10000) then
    ShowMessage('Connect failed: ' + vError);
end;

Mehr dazu: async / await in Delphi.

Härtung des HTTP Clients

Eine Weiterleitung ist der einfachste Weg, ein Token zu verlieren. Wenn ein Server Ihre authentifizierte Anfrage mit einem 302 auf einen anderen Host beantwortet, schickt der Client die Header Authorization und Cookie bereitwillig auch dorthin. 2026.7 fügt StripAuthOnCrossHostRedirect hinzu, um sie bei einer Weiterleitung auf eine andere Site zu entfernen, und NoInsecureRedirect, um eine Weiterleitung abzulehnen, die HTTPS auf einfaches HTTP herabstuft.

Antworten lassen sich jetzt ebenfalls begrenzen, mit MaxChunkSize für ein einzelnes Stück einer Chunked-Antwort und MaxResponseSize für die Gesamtgröße. RejectPublicSuffixCookies verwirft Cookies, die für allzu breite Domänen wie "com" oder "co.uk" beansprucht werden. Für Uploads gibt es Expect: 100-continue, womit der Server um Erlaubnis gebeten wird, bevor ein großer Body gesendet wird, sowie einen Chunked Request Body, um einen Upload zu streamen, dessen Größe Sie noch nicht kennen.

oHTTP.StripAuthOnCrossHostRedirect := True;
oHTTP.NoInsecureRedirect           := True;
oHTTP.MaxResponseSize              := 10 * 1024 * 1024;  // 10 MB, 0 = unlimited
oHTTP.MaxChunkSize                 := 1024 * 1024;       // 1 MB per chunk
oHTTP.RejectPublicSuffixCookies    := True;

All diese Schalter sind standardmäßig aus, und keiner davon verlangt, dass Sie zum HTTP-Objekt auf der unteren Ebene greifen: Sie sind ebenso auf den fertigen API-Clients veröffentlicht (AI/LLM, Krypto-Börsen, OAuth2, Google Cloud, WhatsApp, AWS SQS, WebPush). Die Weiterleitungs- und Größenschutzmechanismen gibt es auch im HTTP/2 Client, und HTTP/3 erhält die Begrenzung der Antwortgröße. Mehr dazu: Härtung des HTTP Clients.

Wiederholungen, Backoff und Jitter

Der WatchDog hat sich früher in einem festen Intervall neu verbunden, was bedeutet, dass tausend Clients, die den Server verlieren, alle im selben Moment zurückkommen. Er unterstützt jetzt exponentielles Backoff mit einem Multiplikator, einer Obergrenze und einem zufälligen Jitter, sodass sich die Flotte verteilt. Das feste Intervall bleibt der Standard, es ändert sich also nichts, bis Sie es anfordern.

Der HTTP Client hat eine eigene Wiederholungsstrategie bekommen: Wiederholung bei einer konfigurierbaren Liste von Statuscodes, jedes Mal länger warten und den Retry-After-Hinweis des Servers beachten, wenn er einen sendet. Die Clients für OpenAI, Anthropic und Gemini nutzen sie ebenfalls.

sgcWebSocketClient1.WatchDog.Backoff           := wdbExponential;
sgcWebSocketClient1.WatchDog.BackoffMultiplier := 2.0;   // double every attempt
sgcWebSocketClient1.WatchDog.MaxInterval       := 60;    // seconds, the ceiling
sgcWebSocketClient1.WatchDog.Jitter            := 0.2;   // up to 20% random spread

Mehr dazu: Exponentielles Backoff, Jitter und Retry-After.

Backpressure auf der Sendewarteschlange

Wenn ein Client langsamer liest, als Sie schreiben, stauen sich die eingereihten Nachrichten im Serverspeicher. Sie können die Anzahl der ausstehenden Nachrichten pro Verbindung jetzt mit QueueOptions.MaxQueueSize begrenzen und wählen, was beim Erreichen der Grenze passiert: die älteste Nachricht verwerfen, die neueste verwerfen oder die Verbindung trennen. Das neue Ereignis OnSendBufferFull wird ausgelöst, bevor etwas verworfen wird, sodass Sie es protokollieren, zählen oder das Verwerfen für eine Verbindung untersagen können, bei der Sie sich Verluste nicht leisten können. Die Warteschlange ist standardmäßig unbegrenzt.

oServer.QueueOptions.MaxQueueSize   := 1000;
oServer.QueueOptions.OverflowPolicy := qopDropOldest;  // or qopDropNewest, qopDisconnect

Mehr dazu: Grenzen für die Sendewarteschlange bei langsamen WebSocket Clients.

gzip und deflate im HTTP Server

Die HTTP Server können ihre Antworten jetzt komprimieren, sobald der Client Accept-Encoding ankündigt. Das gilt für Dateien, die aus DocumentRoot ausgeliefert werden, und für Antworten, die Sie selbst in OnCommandGet aufbauen. Bodies unterhalb einer Mindestgröße und Inhaltstypen, die dadurch nicht kleiner würden, werden übersprungen, und es steht auch im HTTP.sys Server zur Verfügung. Die Komprimierung ist standardmäßig aus, und vorerst werden nur HTTP/1.1-Antworten komprimiert.

sgcWebSocketHTTPServer1.HTTPCompression.Enabled := True;
sgcWebSocketHTTPServer1.HTTPCompression.Level   := 6;     // 1..9
sgcWebSocketHTTPServer1.HTTPCompression.MinSize := 1024;  // bytes

Mehr dazu: gzip- und deflate-Komprimierung im HTTP Server.

Die HTTP QUERY Methode

QUERY ist eine neue HTTP-Methode der IETF, die eine Suche wie ein POST im Request Body sendet, dabei aber sicher und cachefähig bleibt wie ein GET, sodass Ihre Abfrage nicht länger in eine URL mit Längenbegrenzung gepresst wird. 2026.7 implementiert sie in den HTTP/1.x-, HTTP/2-, HTTP/3- und REST-Clients, und die Server sowie der Proxy verarbeiten sie.

vResult := oClient.Query('https://api.example.org/contacts', oQuery);

Mehr dazu: Die neue HTTP QUERY Methode in Delphi.

E2EE Identitätsprüfung

Die Ende-zu-Ende-Verschlüsselung hält die Nutzdaten privat, aber für sich genommen sagt sie Ihnen nicht, wer am anderen Ende ist. Ein Server oder ein Relay in der Mitte kann jeder Seite einen eigenen Schlüssel unterschieben und alles mitlesen. In 2026.7 kann jede Seite ihren Verschlüsselungsschlüssel mit einem langlebigen Identitätsschlüssel signieren, und die Gegenseite prüft diese Signatur, sodass ein stiller Schlüsseltausch erkannt statt akzeptiert wird.

Es funktioniert für Eins-zu-eins- und für Gruppenchats, bringt Ereignisse mit, um die Identität einer Gegenstelle zu bestätigen oder festzupinnen und um Sie zu warnen, wenn sich der Identitätsschlüssel einer Gegenstelle ändert, und es ist standardmäßig aus und vollständig abwärtskompatibel mit Gegenstellen unter 2026.6.

E2EE.E2EE_Options.Identity.Enabled    := True;
E2EE.E2EE_Options.Identity.PrivateKey := LoadIdentityPrivateKey;  // PEM
E2EE.E2EE_Options.Identity.PublicKey  := LoadIdentityPublicKey;   // PEM
E2EE.OnE2EEVerifyPeerIdentity := OnE2EEVerifyPeerIdentityEvent;
E2EE.OnE2EEKeyChange          := OnE2EEKeyChangeEvent;

Mehr dazu: E2EE Identitätsprüfung.

OAuth2 für den MCP Client und der Identity Assertion Grant

Der MCP Client kann sich jetzt mit OAuth2 statt mit einem statischen API Key authentifizieren. Er holt das Token selbst, speichert es zwischen, bis es abläuft, und erneuert es, und wenn OAuth2 aktiviert ist, hat es Vorrang vor dem API Key. Daneben erhält der OAuth2 Client einen neuen Grant-Typ, den Identity Assertion Authorization Grant, der eine Identität aus einer Domäne in eine andere verkettet: Der Client führt den gesamten mehrstufigen Austausch für Sie aus und löst Ereignisse aus, sodass Sie jedem Schritt folgen können.

MCPClient.MCPOptions.AuthenticationOptions.OAuth2.Enabled := True;
MCPClient.MCPOptions.AuthenticationOptions.OAuth2.GrantType := auth2ClientCredentials;
MCPClient.MCPOptions.AuthenticationOptions.OAuth2.TokenURL := 'https://auth.example.com/oauth2/token';
MCPClient.MCPOptions.AuthenticationOptions.OAuth2.ClientId := 'YOUR_CLIENT_ID';
MCPClient.MCPOptions.AuthenticationOptions.OAuth2.ClientSecret := 'YOUR_CLIENT_SECRET';

Mehr dazu: OAuth2 für den MCP Client.

Krypto-Feeds: erneutes Abonnieren und Ratenbegrenzung

Wenn bisher ein Marktdaten-Socket abbrach und der WatchDog ihn zurückbrachte, war der Socket zwar oben, Sie hatten aber nichts abonniert, bis Sie jedes Abonnement selbst wiederholten. Die Börsen-Clients können das jetzt für Sie erledigen: Setzen Sie Resubscribe := True, und Ihre Streams werden nach einer Neuverbindung wiederhergestellt. Das deckt Binance, Kraken, Coinbase und rund vierzehn weitere Börsen ab, dazu den sitzungsbasierten Feed von XTB. Standardmäßig ist es False.

Die REST-API-Clients erhalten einen optionalen clientseitigen Rate Limiter, damit ein Schwall von Anfragen Sie nicht zeitweilig von einer Börse sperren lässt. Begrenzen Sie, wie viele Anfragen Sie in einem Zeitfenster senden, und wählen Sie, ob eine überzählige Anfrage wartet oder abgelehnt wird. Standardmäßig aus.

oBinance.RateLimit.Enabled     := True;
oBinance.RateLimit.IntervalMs  := 60000;   // one minute window
oBinance.RateLimit.MaxRequests := 1000;
oBinance.RateLimit.Behavior    := rlbWait;

Mehr dazu: Erneutes Abonnieren und der clientseitige Rate Limiter.

Kleinere Ergänzungen

Fehlerbehebungen und Härtung

2026.7 bringt eine lange Liste von Fehlerbehebungen mit. Statt sie alle zu wiederholen, hier, worauf sie hinauslaufen.

Speichersicherheit und Härtung der Parser. Lesezugriffe über das Ende des Puffers hinaus wurden im MQTT 5 Client behoben (ein Broker, der mehr Daten behauptet, als er gesendet hat), im AMQP 1.0 Client (UUID-Dekodierung), im STUN/TURN Parser (einschließlich einer Endlosschleife und IPv6-Adressen), im WebRTC SCTP Datenkanal und im Rohdaten-TCP-Frame-Scanner. Der UDP Client und Server, einschließlich DTLS, geben einen Socket nicht mehr doppelt frei und lassen ihn beim Trennen nicht mehr hängen. Dort, wo eine sich fehlverhaltende Gegenstelle sonst den Speicher unbegrenzt hätte wachsen lassen können, wurden interne Obergrenzen ergänzt: die Warteschlange der ausstehenden MQTT-Nachrichten, die Abonnements pro Verbindung im sgc-Protokoll, die ausstehenden Aufrufe des WAMP Servers, die Trailer-Zeilen einer Chunked-Antwort und die Verschachtelungstiefe von AMQP-Feldtabellen.

HTTP/2. Eine Obergrenze für die dekomprimierte Größe (standardmäßig 64 MB) schließt ein Speicherleck-Loch bei "Zip-Bomben"-Antworten, die Begrenzung der Antwortgröße lässt sich nicht mehr über den letzten Teil einer Antwort umgehen, und eine fehlgeschlagene Anfrage schlägt jetzt sofort fehl, statt den gesamten Timeout abzuwarten.

Kryptografie und Zufallszahlen. Der WebAuthn Server, der OAuth2 Autorisierungsserver und die eingebauten HTTP-Sitzungs-IDs verwenden jetzt einen kryptografisch sicheren Zufallsgenerator, Challenges sind nur einmal verwendbar, und Geheimnisse werden in konstanter Zeit verglichen (Client Secret, JWT-Signatur, Basic-Passwort der HTTP API). Ein JWT mit gültiger Signatur, aber fehlerhaftem Claim wird jetzt abgelehnt statt akzeptiert. Mit aktiviertem StrictVerify in OpenSSL wird das Zertifikat auch gegen den Hostnamen geprüft, ein gültiges Zertifikat, das für einen anderen Host ausgestellt wurde, wird also abgelehnt. Verbindungen zu einer IP-Adresse und bestehende Einstellungen sind davon nicht betroffen.

Server-Sent Events. Eine gestreamte Antwort, die mehrere Ereignisse in einem Lesevorgang lieferte, oder ein Ereignis, das sich über zwei Lesevorgänge verteilte, verlor alle bis auf das erste. Das ist behoben, womit das Token-für-Token-Streaming für die AI/LLM-Clients wiederhergestellt ist. Der OpenAI Streaming Chat setzte außerdem das Stream-Flag nicht, er streamt jetzt also wie die anderen Anbieter.

Börsen-Clients. Kraken-Request-IDs sind jetzt streng aufsteigend, BitMEX sendet seine Ablaufzeit in Sekunden statt in Millisekunden, MEXC signiert die kodierten Parameter, die es tatsächlich sendet, Cryptorobotics vertauscht bei By-Hash-Aufrufen keine zwei Werte mehr, Deribit erneuert sein Login-Token, bevor es abläuft, und der Forex Client meldet den Fehler, den er beim Lesen der Konto-ID früher verschluckt hat.

Lazarus und Free Pascal. Drei Kompilierungskorrekturen: Die Interfaces der JSON Unit verwenden jetzt die je nach Plattform richtige Aufrufkonvention (sie ließen sich unter Linux nicht kompilieren), der Forex Client ruft keine Delphi-exklusive Funktion mehr auf, um das Zahlenformat zu lesen, und die Unit für den Post-Quantum-Schlüsselaustausch hängt nicht mehr von size_t ab.

Mehr steht in history.txt, darunter der gRPC Client (gleichzeitige Aufrufe konnten die Antworten der jeweils anderen empfangen, und ein Sendefehler wurde als Erfolg gemeldet), der OpenAPI Server (das Laden der Spezifikation ist jetzt threadsicher, und Ihre Handler laufen nicht mehr, während eine interne Sperre gehalten wird), ein Leck bei Serververbindungen und Sockets bei jeder fehlgeschlagenen Anmeldung, ein Absturz bei OpenAI-Antworten ohne "message"-Feld, wie sie etwa von Ollama und LM Studio kommen, ein korrigiertes WriteAndWaitData im WinHTTP Client und die Schwärzung von Geheimnissen im Protokoll des HTTP Clients, sodass das Einschalten der Protokollierung keine Tokens mehr im Klartext auf die Festplatte schreibt.

Die .NET Edition

sgcWebSockets .NET 2026.7 konzentriert sich auf den HTTP Client. Es liefert denselben Satz an Schutzmechanismen wie die Delphi Edition: Entfernen der Zugangsdaten bei einer Weiterleitung auf eine andere Site, Blockade eines Downgrades von HTTPS auf HTTP, Obergrenzen für die Größe pro Chunk und insgesamt, Ablehnung von Public-Suffix-Cookies, Expect: 100-continue und Chunked Request Bodies. Sie stehen auf den HTTP-Client-Komponenten und auf den fertigen API-Clients zur Verfügung (die AI/LLM-Clients, OAuth2, Google Cloud, WhatsApp, AWS SQS, WebPush), und dieselben Weiterleitungs- und Größenschutzmechanismen gibt es im HTTP/2 Client. Die Korrekturen an der Weiterleitungsbehandlung und am Cookie-Ablauf sind ebenfalls enthalten. Alles ist standardmäßig aus.

Umstieg

2026.7 ist ein Drop-in-Upgrade für bestehende 2026.x-Projekte. Jede neue Funktion dieser Version ist standardmäßig aus: Clustering, Nachrichtenhistorie, Backoff, die Begrenzung der Sendewarteschlange, die HTTP-Komprimierung, die Client-Schutzmechanismen, die E2EE Identitätsprüfung und das erneute Abonnieren bei den Börsen müssen alle ausdrücklich eingeschaltet werden. Die Installation des neuen Builds ändert also kein Verhalten, bis Sie sich dafür entscheiden.

Kunden mit einem aktiven Abonnement können den neuen Build im Kundenbereich herunterladen oder unter esegece.com/products/websockets/download.

Fragen, Feedback oder Hilfe beim Umstieg? Nehmen Sie Kontakt auf. Sie erhalten eine Antwort von den Leuten, die den Code geschrieben haben.