TCP
TcpSocketActor umschließt eine clientseitige TCP-Verbindung.
Zum Lauschen auf einem Port (eingehende TCP-Verbindungen
annehmen) lautet das Framework-Muster: “spawne pro eingehender
Verbindung von einem Listener-Actor genau einen Client-Actor”.
import { ActorSystem, Props, TcpSocketActor } from 'actor-ts';
const tcp = system.spawn( Props.create(() => new TcpSocketActor({ host: 'metrics-collector.example.com', port: 8125, })), 'tcp-client',);
// Rohe Bytes senden:tcp.tell({ kind: 'send', payload: new Uint8Array([0x01, 0x02, 0x03]) });
// Oder Text:tcp.tell({ kind: 'send-text', payload: 'PING\n' });
// Eingehende Bytes subscribieren:tcp.tell({ kind: 'subscribe', subscriber: protocolHandler });Settings
Abschnitt betitelt „Settings“interface TcpSocketActorSettings extends BrokerCommonSettings { host: string; port: number; keepAlive?: boolean; keepAliveDelay?: number; noDelay?: boolean; // Nagles Algorithmus deaktivieren framer?: TcpFramer; // optionale Frame-Parsing-Schicht}Eingehende Nachrichten
Abschnitt betitelt „Eingehende Nachrichten“import { match } from 'ts-pattern';
class ProtocolHandler extends Actor<TcpInbound> { override onReceive(msg: TcpInbound): void { match(msg) .with({ kind: 'data' }, (m) => this.handleBytes(m.payload)) // Uint8Array .with({ kind: 'connected' }, () => { this.log.info('TCP verbunden'); }) .with({ kind: 'disconnected' }, () => { this.log.info('TCP getrennt'); }) .exhaustive(); }}Jede data-Nachricht trägt einen Chunk Bytes — KEINE logische
Nachricht. TCP ist ein Byte-Stream; Framing ist dein Job.
Framing
Abschnitt betitelt „Framing“import { LengthPrefixedFramer } from 'actor-ts';
new TcpSocketActor({ host, port, framer: new LengthPrefixedFramer({ prefixSize: 4 }),});Optionaler Framer, der den Byte-Stream in diskrete Nachrichten parst. Das Framework liefert:
LengthPrefixedFramer— 4-Byte- (konfigurierbares) Längen- Prefix.DelimitedFramer— zeilen-delimited oder durch eine bestimmte Byte-Folge abgeschlossen (Newline, NUL usw.).- Custom — implementiere
TcpFramerfür Protokolle wie HTTP/1.1, redis-protocol usw.
Mit einem Framer enthält die data-Nachricht von TcpInbound
einen vollständigen Frame, nicht beliebige Chunks.
Listener-Muster für eingehend
Abschnitt betitelt „Listener-Muster für eingehend“Das Framework liefert keinen “TCP-Listener-Actor” — schreib einen,
der pro angenommener Verbindung TcpSocketActor-ähnliche Handler
spawnt:
// In einem Init-Actor:import net from 'node:net';
const server = net.createServer((socket) => { const handler = system.spawn( Props.create(() => new IncomingConnectionActor(socket)), );});server.listen(port, host);Für die meisten Anwendungsfälle gilt: bau dir keinen eigenen TCP-Server — nimm stattdessen HTTP, WebSocket oder ein höherrangiges Protokoll.
Wann TCP
Abschnitt betitelt „Wann TCP“Drei legitime Einsatzfälle:
- Mit Legacy-Protokollen sprechen — proprietäre Protokolle, für die es keine höherrangigen Wrapper gibt.
- Eigene Binärprotokolle — Game-Server, Metric-Collector mit eigenem Wire-Format.
- Brücken zu Nicht-HTTP-Services — Message-Queues mit proprietärem Wire (z. B. einige Finanzprotokolle).
Für neue Anwendungsprotokolle gilt: greife nicht zuerst zu raw TCP. HTTP, WebSocket oder gRPC sind für fast alles die besseren Startpunkte.
Wohin als Nächstes
Abschnitt betitelt „Wohin als Nächstes“- I/O-Übersicht — das große Bild.
- BrokerActor-Basis — der gemeinsame Lifecycle.
- UDP — die verbindungslose Alternative.
- gRPC — typisierter RPC über HTTP/2 — meist die bessere Wahl als raw TCP.