Sockets
Nutze einen SDK-Socket, um den TCP- oder UDP-Client deiner Anwendung über ein URnetwork-Device zu verbinden. Lesen, Schreiben, Deadlines und Schließen funktionieren wie gewohnt, während sein Datenverkehr dem gewählten Verbindungspfad des Device folgt. Du kannst ihn für einen einzelnen Client nutzen, ohne den Rest der Maschine durch ein VPN des Betriebssystems zu routen.
Beginne mit einem initialisierten Device aus Erste Schritte mit dem SDK. Die Socket-Methoden sind im aktualisierten SDK-Quellcode verfügbar und setzen passende Socket-Unterstützung auf einem Remote-Device voraus. Nutze auf beiden Seiten einer RPC-Verbindung SDK-Builds, die diese APIs enthalten.
Die Befehle für die nativen Paketmanager findest du unter Das SDK installieren, lauffähige Socket- und HTTP-Bibliotheks-Integrationen in zwölf Sprachen unter Beispiele, darunter getrennte JavaScript-Programme für Node und den Browser.
Wie sich ein SDK-Socket von einem Kernel-Socket unterscheidet
Ein Kernel-Socket gehört zum Netzwerk-Stack des Betriebssystems. Ein SDK-Socket gehört zum Device und nutzt einen prozessinternen TCP/IP-Stack. Das Device sendet seine Pakete über seine konfigurierte Route, einschließlich des gewählten Providers, wenn es über URnetwork verbunden ist.
| Kernel-Socket | SDK-Socket | |
|---|---|---|
| Netzwerkpfad | Routing-Tabelle des OS und Auswahl des Interface | Routing des Device, Auswahl des Providers und Richtlinien |
| Anwendungsschnittstelle | File-Descriptor oder Socket-Objekt der Plattform | Go net.Conn, JS Conn, C-Handle oder mobiles Socket |
| Geltungsbereich | Anwendungsverbindung im Netzwerk des Hosts | Anwendungsverbindung, die einem einzelnen Device gehört |
| System-VPN für diese Verbindung nötig | Hängt davon ab, wie die Route des OS konfiguriert ist | Allein für Aufrufe von SDK-Sockets ist kein TUN/VPN-Interface des OS nötig |
| Lokale Adresse | Interface/Adressraum des Hosts | Virtuelle Adresse im Userspace-Stack des Device |
| Schließen des Device | Keine Beziehung | Schließt seine SDK-Verbindungen |
| Socket-Optionen und Listener | Plattformabhängige APIs des OS | Nur ausgehende Verbindungen; kein File-Descriptor, keine beliebigen Socket-Optionen, keine Listen-API |
Die virtuelle localAddr ist nicht die öffentliche Exit-IP des Providers, und sich an sie zu binden macht deine App nicht aus dem Internet erreichbar. Die zugrunde liegende URnetwork-Verbindung und der Provider können weiterhin das Networking des Betriebssystems nutzen. Ein SDK-Socket ändert weder den konfigurierten Routing-Modus des Device, noch baut er von sich aus eine Verbindung zu einem Provider auf.
TLS und DTLS verschlüsseln die Anwendungsverbindung bis zu ihrem Ziel. Schlichtes TCP und UDP lassen das Klartextprotokoll der Anwendung unverändert; die Transportverschlüsselung von URnetwork bis zu einem Provider macht aus diesem Protokoll kein TLS zum Ziel.
Netzwerke und Hostnamen
Baue die Verbindung zu einem host:port mit einem dieser Netzwerke auf:
| Netzwerk | Verhalten |
|---|---|
tcp | TCP mit Happy Eyeballs über IPv4/IPv6 für einen Hostnamen |
tcp4, tcp6 | TCP, auf diese Adressfamilie beschränkt |
udp | UDP; ein Hostname mit beiden Adressfamilien wählt seinen Peer per Wettlauf des ersten Datagramms bzw. der ersten Antwort |
udp4, udp6 | UDP, auf diese Adressfamilie beschränkt |
Setze IPv6-Literale in eckige Klammern, zum Beispiel [2001:db8::10]:443. Die Namensauflösung nutzt den Socket-Resolver und den Paketpfad des Device. Ist kein Provider verfügbar, fällt sie nicht darauf zurück, das Ziel direkt über den Host aufzulösen oder zu öffnen.
TCP-Happy-Eyeballs lässt Verbindungsversuche gegeneinander laufen. TLS-/DTLS-Dialer wählen eine Adressfamilie erst, nachdem ihr sicherer Handshake gelungen ist. Explizite Familiennamen und literale Adressen umgehen den Wettlauf zwischen den Familien.
UDP: mögliche doppelte Zustellung
UDP hat keinen Verbindungs-Handshake. Bei udp mit A- und AAAA-Einträgen geht der erste Schreibvorgang an IPv6 und nach 250 ms ohne Antwort an IPv4. Scheitert der Schreibvorgang über IPv6 sofort, beginnt der Fallback früher. Das erste Datagramm der Anwendung kann beide Adressen erreichen. Die erste Antwort wählt den Peer, und spätere Schreibvorgänge gehen nur noch an diesen Peer.
Nutze Request-IDs oder einen anderen Mechanismus auf Anwendungsebene für den Umgang mit Duplikaten, wenn doppelte Zustellung eine Rolle spielt. Ein erfolgreicher erster Schreibvorgang beweist weder die Zustellung, noch wählt er einen Peer. Antwortet der Server nie, warten spätere Schreibvorgänge auf die Auswahl, bis ihre Deadline erreicht ist oder die Verbindung geschlossen wird. Für Protokolle, die nur senden, nutze udp4, udp6 oder eine literale IP. Eine Antwort mit null Bytes ist eine gültige Antwort.
Jeder UDP-Schreibvorgang ist ein Datagramm. Jeder Lesevorgang verbraucht ein Datagramm; ein kleiner Lesepuffer verwirft die restlichen Bytes. Ein leeres Datagramm zählt als Daten, nicht als EOF. Halte Nachrichten innerhalb der Grenzen des Zielprotokolls und des Pfads.
Go
DeviceLocal und DeviceRemote bieten Dial, DialContext, DialTls und DialTlsContext. Die gewöhnlichen Dial-Methoden haben dieselben Signaturen wie Gos net.Dialer und geben eine net.Conn-kompatible Verbindung zurück.
// device is an initialized sdk.Device.
conn, err := device.DialContext(ctx, "tcp", "example.com:80")
if err != nil {
return err
}
defer conn.Close()
if err := conn.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
return err
}
_, err = conn.Write([]byte("GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"))Ein bestehender HTTP-Client kann das Device direkt nutzen:
transport := &http.Transport{DialContext: device.DialContext}
defer transport.CloseIdleConnections()
client := &http.Client{Transport: transport, Timeout: 20 * time.Second}
// net/http performs normal HTTPS certificate verification above this dialer.Für direkte Verschlüsselung rufst du device.DialTlsContext(ctx, "tcp", "example.com:443", nil) auf. TCP nutzt TLS; UDP nutzt DTLS 1.2. Ist die TLS-Konfiguration nil, gilt die normale Zertifikatsprüfung. Der ursprüngliche Hostname liefert den Standard-Servernamen. DTLS unterstützt eine kleinere Konfigurationsfläche als Go-TLS und lehnt nicht unterstützte Sicherheitsoptionen ab.
Lese- und Schreibvorgänge können Teildaten zusammen mit einem Fehler zurückgeben; verarbeite die zurückgegebenen Bytes. Ein Dial-Context steuert den Verbindungsaufbau, nicht die Lebensdauer einer erfolgreich aufgebauten Verbindung. Setze absolute Deadlines für nachfolgende I/O und lösche sie mit time.Time{}. Schließ die Verbindung, wenn du fertig bist. Die Standardgrenze für Verbindungsaufbau und sicheren Handshake beträgt 30 Sekunden und verkürzt sich durch eine frühere Deadline des Aufrufers.
JavaScript und TypeScript
Die Device-Wrapper des SDK bieten Promise-basierte Methoden dial und dialTls. Eine Browser-Seite nutzt ein konfiguriertes Remote-Device, das Sockets unterstützt. Das SDK stellt die Remote-Verbindung über WASM bereit; es braucht weder native Unterstützung für Direct Sockets im Browser noch eine Paketierung als Isolated Web App.
const conn = await device.dialTls("tcp", "example.com:443", undefined, {
timeoutMillis: 5000,
});
try {
await conn.setDeadline(Date.now() + 5000);
await conn.write(new TextEncoder().encode(
"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"
));
for (let chunk; (chunk = await conn.read()) !== null;) {
console.log(new TextDecoder().decode(chunk));
}
} finally {
await conn.close();
}read() gibt ein Uint8Array zurück, oder null bei EOF. Ein leeres Array ist ein gültiges UDP-Datagramm. readable und writable stellen Adapter für Web Streams bereit; wähle pro Richtung entweder die direkten Methoden oder die Adapter. Das Schließen eines TCP-Streams sendet ein FIN auf der Schreibseite, wo das unterstützt wird. Ein explizites close() schließt die gesamte Verbindung.
Nutze ein AbortSignal, um das Öffnen abzubrechen. Bei aufgebauten Sockets nutzt du Deadlines und Schließen. Deadline-Methoden akzeptieren Epoch-Millisekunden, ein Date oder null zum Löschen. Ein Fehler bei einem teilweisen Schreibvorgang enthält bytesWritten; teilweise gelesene Daten werden zuerst zurückgegeben, der zugehörige Fehler folgt beim nächsten direkten Lesevorgang. Der Socket-Datenverkehr stoppt, wenn sich der besitzende Remote-Dienst trennt; nach der Wiederverbindung wird er nicht erneut abgespielt.
Direct Sockets API
Nutze die Konstruktor-Signaturen von Direct Sockets mit einem UR-Device:
const {TCPSocket, UDPSocket} = device.directSockets;
const socket = new TCPSocket("echo.example", 9000);
const {readable, writable} = await socket.opened;
const reader = readable.getReader({mode: "byob"});
const writer = writable.getWriter();
try {
await writer.write(new TextEncoder().encode("hello"));
await writer.close();
console.log(await reader.read(new Uint8Array(1024)));
} finally {
await Promise.allSettled([reader.cancel(), writer.abort()]);
reader.releaseLock(); writer.releaseLock();
await socket.close();
await socket.closed;
}Für UDP konstruierst du new UDPSocket({remoteAddress: "echo.example", remotePort: 9001}). Warte auf opened, schreibe dann {data: new Uint8Array([1, 2, 3])} und lies value.data. Jedes Objekt ist ein Datagramm, auch ein Datagramm mit null Bytes. Nachrichten über verbundenes UDP lassen die Felder für die Remote-Adresse weg und lehnen Zielüberschreibungen pro Nachricht ab.
Die exportierte Factory createDirectSockets(device) gibt diese Konstruktoren ebenfalls zurück. Beide Schnittstellen haben die Promises opened und closed und ein asynchrones close(). TCP unterstützt Standard- und BYOB-Reader sowie Schreibvorgänge mit BufferSource. Das Schließen seines beschreibbaren Streams sendet FIN, während das Lesen weiter möglich bleibt. Brich ausstehende Operationen per cancel/abort ab und gib die Reader-/Writer-Locks frei, bevor du einen Socket schließt; andernfalls lehnt close() mit InvalidStateError ab. Bei Netzwerkfehlern wird mit NetworkError abgelehnt.
Die native API von Chrome steht Isolated Web Apps zur Verfügung. Die Implementierung des SDK funktioniert in gewöhnlichen Browsern und in Node über das konfigurierte Device, ohne IWA-Paket und ohne native Berechtigung für Direct Sockets. Sie ersetzt keine Globals des Browsers. Siehe die Chrome-Dokumentation und den Vorschlag für Direct Sockets.
Dieses Release implementiert ausgehendes TCP und verbundenes UDP. Nutze dnsQueryType: "ipv4" oder "ipv6", um die Auflösung einzuschränken; lässt du es weg, bleibt Happy Eyeballs des Device erhalten. Gebundenes UDP, Multicast, Listener und das Tuning von Puffer, No-Delay und Keep-Alive pro Socket sind nicht verfügbar, und gültige Anfragen nach diesen Funktionen scheitern mit NotSupportedError. Das ist ein Kompatibilitätsprofil für Clients, nicht die vollständige Browser-API.
Bei UDP-Namen mit beiden Adressfamilien wird opened schon vor dem Senden erfüllt. Seine Endpunktfelder beschreiben zunächst den ersten Kandidaten und werden aktualisiert, sobald die erste Antwort verarbeitet ist. Das erste Datagramm kann beide Adressen erreichen. Wähle eine literale IP oder eine DNS-Familie, wenn du beim Öffnen einen festen Endpunkt brauchst. Die Beispiele nutzen einen Timer, um stockende Stream-I/O abzubrechen; die separate Conn-API bietet außerdem Deadlines.
Die Konstruktoren von Direct Sockets öffnen schlichte TCP-/UDP-Verbindungen. Für TLS/DTLS nutze dialTls. Die lauffähigen JavaScript-Beispiele für Node und den Browser und das TypeScript-Beispiel enthalten TCP-/UDP-Echo, Timeouts, Aufräumen und die Integration von HTTP-Bibliotheken.
Native Bindings und unterstützte Plattformen
| Binding | Socket-Fläche und Plattform |
|---|---|
| Go | net.Conn-Verhalten auf den vom SDK unterstützten Go-Targets |
| Android Kotlin/Java | Portables OpenSocket/Socket im AAR; Android API 24+ mit den ausgelieferten ABIs |
| Apple Swift | Portables OpenSocket/Socket im XCFramework; iOS 16+ und macOS 13.5+ mit den ausgelieferten Geräte-/Simulator-Slices |
| C/C++ und andere FFI-Clients | C-ABI für Windows 10+ und Linux glibc 2.35+ auf amd64/arm64; macOS-Host-Builds für die Entwicklung |
| Browser und Node JS/TS | WASM, Web Streams für Conn und Direct Sockets, dazu ein verfügbarer socketfähiger Device-RPC-Endpunkt |
Mobile Aufrufer nutzen OpenSocket(network, address, timeoutMillis, tlsOptions). Sind die TLS-Optionen nil, wird eine schlichte Verbindung angefordert; eine Konfiguration ungleich nil fordert TLS/DTLS an. Socket.Read gibt ein Ergebnis mit Data und Eof zurück; Deadline-Methoden nehmen Epoch-Millisekunden, und Null löscht die Deadline. Nutze für blockierende Operationen einen Worker-Thread oder einen passenden Coroutine-Dispatcher.
C-Aufrufer nutzen urnet_device_dial / urnet_device_dial_tls, gefolgt von urnet_conn_read, urnet_conn_write und den Funktionen für Deadline und Schließen. Read gibt eine Byte-Anzahl und ein separates EOF-Flag zurück. Der Aufruf verbraucht Daten sofort; er ist keine Abfrage der Größe des Ausgabepuffers. Verarbeite gemeldete Teil-Byte-Anzahlen auch dann, wenn ein Fehlerstring zurückgegeben wird. Gib Fehler- und Adressstrings mit urnet_free_string frei, und gib das Verbindungs-Handle mit urnet_release frei; dieser Aufruf schließt die Verbindung dabei auch.
Das SDK bietet derzeit Client-Verbindungen. Server-/Listener-Sockets kommen als separate Ergänzung, mit expliziter Semantik für Erreichbarkeit und Besitz. Das Binding- und Build-Modell beschreibt die SDK-Tour, die Einrichtung des Device Erste Schritte.