UDP
UdpSocketActor umschließt einen UDP-Socket — verbindungslos, keine
ACKs, keine Retries, paketorientiert. Nimm ihn, wenn Best-Effort-
Zustellung in Ordnung ist und Latenz wichtiger ist als
Zuverlässigkeit.
Eingehende Datagramme werden an einen Target-Actor geschoben, den
du über den Builder verdrahtest — es gibt kein Subscribe-Kommando.
Gesendet wird per { kind: 'send', datagram }-Nachricht mit
explizitem Ziel (UDP ist verbindungslos, jedes Paket trägt also seine
eigene Adresse).
import { ActorSystem, UdpSocketActor, UdpSocketOptions } from 'actor-ts';import type { UdpDatagram } from 'actor-ts';
const system = ActorSystem.create('udp-demo');
// Inbound datagrams land here, one message per packet:class PacketHandler extends Actor<UdpDatagram> { override onReceive(d: UdpDatagram): void { // d.payload — Uint8Array // d.remoteHost — sender's address // d.remotePort — sender's port console.log(new TextDecoder().decode(d.payload), 'from', d.remoteHost); }}
const target = system.spawnAnonymous(PacketHandler);
const udpSocketOptions = UdpSocketOptions.create() .withBindPort(41234) // bind for receiving; 0 lets the OS pick .withTarget(target);const udp = system.spawnAnonymous( () => new UdpSocketActor( udpSocketOptions, // required: where inbound packets go ),);
// Send to a remote endpoint:udp.tell({ kind: 'send', datagram: { payload: 'ping', host: '127.0.0.1', port: 41234 },});Settings
Abschnitt betitelt „Settings“UdpSocketOptionsType erweitert BrokerCommonOptionsType (das die
gemeinsamen Felder für Reconnect / Circuit-Breaker / Outbound-Buffer
mitbringt) und ergänzt:
interface UdpSocketOptionsType extends BrokerCommonOptionsType { bindHost?: string; // default '0.0.0.0' bindPort?: number; // default 0 = OS-assigned type?: 'udp4' | 'udp6'; // default 'udp4' target?: ActorRef<UdpDatagram>; // required: inbound subscriber}target ist das einzige Pflichtfeld — ohne es haben eingehende
Datagramme kein Ziel. Alle vier werden über den Builder gesetzt:
UdpSocketOptions.create() .withBindHost('0.0.0.0') .withBindPort(41234) .withType('udp4') .withTarget(target);Empfangen
Abschnitt betitelt „Empfangen“Eingehende Pakete werden direkt an den target-Actor zugestellt — eine
UdpDatagram-Nachricht pro Paket. Es gibt kein subscribe-Handshake;
das Verdrahten des Targets über .withTarget(..) ist bereits die
gesamte Subscription:
class PacketHandler extends Actor<UdpDatagram> { override onReceive(d: UdpDatagram): void { // d.payload — Uint8Array (packet bytes) // d.remoteHost — sender's IP address // d.remotePort — sender's port this.handleDatagram(d.payload, d.remoteHost, d.remotePort); }}
const target = system.spawnAnonymous(PacketHandler);
const udpSocketOptions = UdpSocketOptions.create() .withBindPort(41234) .withTarget(target);const udp = system.spawnAnonymous( () => new UdpSocketActor( udpSocketOptions, ),);Jedes Paket ist eine logische Nachricht — UDP erhält
Paketgrenzen (anders als TCPs Byte-Stream), ein eingehendes Datagramm
wird also auf genau ein UdpDatagram abgebildet.
Gesendet wird per { kind: 'send', datagram }-Nachricht. Das
Datagramm trägt sein eigenes Ziel — host und port — plus die
payload, die ein string sein darf (wird für dich UTF-8-kodiert)
oder ein rohes Uint8Array (wird unverändert gesendet):
udp.tell({ kind: 'send', datagram: { payload: 'ping', host: '127.0.0.1', port: 41234 },});
udp.tell({ kind: 'send', datagram: { payload: new Uint8Array([0xde, 0xad]), host: '10.0.0.5', port: 8125 },});Nur Senden
Abschnitt betitelt „Nur Senden“Ein target ist Pflicht, aber wenn der Actor ausschließlich sendet,
kannst du das Binden dem OS überlassen. Lass withBindPort weg (oder
übergib 0), und der Socket bindet an einen ephemeren Port — ein
reiner Sender für einseitige Telemetrie (statsd, syslog):
const udpSocketOptions = UdpSocketOptions.create().withTarget(target);new UdpSocketActor( udpSocketOptions, // OS-assigned port, send-only in practice);Wann UDP
Abschnitt betitelt „Wann UDP“Drei gute Einsatzfälle:
- Telemetrie — Metriken an einen Collector senden (statsd, DogStatsD). Verlust eines Pakets ist akzeptabel; Latenz zählt.
- Service Discovery im LAN — mDNS / SSDP / proprietäre Broadcast-Schemata.
- Hochfrequente Low-Stakes-Daten — Spielpositionen, Sensor-Streams, bei denen das nächste Paket das vorherige ersetzt.
Nicht die richtige Form für:
- Alles, was Zustellgarantie braucht — nimm TCP oder ein höherrangiges, zuverlässiges Protokoll.
- Alles, was Reihenfolge braucht — UDP-Pakete kommen in beliebiger Reihenfolge an.
- Alles, das größer als die MTU ist — Pakete >1500 Bytes fragmentieren + können leichter verloren gehen.
Settings lösen sich mit der üblichen Präzedenz auf — explizite
Builder-Optionen überschreiben HOCON, das wiederum die eingebauten
Defaults überschreibt. Der Config-Namespace ist
actor-ts.io.broker.udp:
actor-ts.io.broker.udp { bindHost = "0.0.0.0" bindPort = 41234 type = "udp4"}Wohin als Nächstes
Abschnitt betitelt „Wohin als Nächstes“- I/O-Übersicht — das große Bild.
- TCP — für verlässliche Byte-Streams.
- BrokerActor-Basis — der gemeinsame Lifecycle.
