Sockets del SDK
Usa un socket del SDK para conectar el cliente TCP o UDP de tu aplicación a través de un Device de URnetwork. Tiene el comportamiento habitual de lecturas, escrituras, plazos (deadlines) y cierre, mientras su tráfico sigue la ruta de conexión que ha seleccionado el Device. Puedes usarlo para un solo cliente sin enrutar el resto de la máquina a través de una VPN del sistema operativo.
Empieza con un Device inicializado, tal como se explica en Primeros pasos con el SDK. Los métodos de socket están disponibles en el código fuente actualizado del SDK y requieren el soporte de sockets correspondiente en un Device remoto. Usa compilaciones del SDK que contengan estas APIs a ambos lados de una conexión RPC.
Consulta Instalar el SDK para los comandos de los gestores de paquetes nativos y Ejemplos para integraciones ejecutables de sockets y de bibliotecas HTTP en doce lenguajes, incluidos programas de JavaScript separados para Node y para el navegador.
En qué se diferencia de un socket del kernel
Un socket del kernel pertenece a la pila de red del sistema operativo. Un socket del SDK pertenece al Device y usa una pila TCP/IP dentro del proceso. El Device envía sus paquetes por su ruta configurada, incluido el proveedor seleccionado cuando está conectado a través de URnetwork.
| Socket del kernel | Socket del SDK | |
|---|---|---|
| Ruta de red | Tabla de enrutamiento y selección de interfaz del sistema operativo | Enrutamiento del Device, selección de proveedor y política |
| Interfaz de aplicación | Descriptor de archivo u objeto socket de la plataforma | net.Conn de Go, Conn de JS, handle de C o Socket en móvil |
| Alcance | Conexión de aplicación en la red del host | Conexión de aplicación propiedad de un Device |
| VPN del sistema necesaria para esta conexión | Depende de cómo esté configurada la ruta del sistema operativo | No hace falta ninguna interfaz TUN/VPN del sistema operativo solo para las llamadas de socket del SDK |
| Dirección local | Espacio de interfaces/direcciones del host | Dirección virtual en la pila en espacio de usuario del Device |
| Cerrar el Device | Sin relación | Cierra sus conexiones del SDK |
| Opciones de socket y listeners | APIs del sistema operativo que dependen de la plataforma | Solo conexiones salientes; sin descriptor de archivo, opciones de socket arbitrarias ni API de escucha |
La localAddr virtual no es la IP pública de salida del proveedor, y enlazarse a ella no hace que tu app sea alcanzable desde Internet. La conexión de URnetwork subyacente y el proveedor pueden seguir usando la red del sistema operativo. Un socket del SDK no cambia por sí solo el modo de enrutamiento configurado del Device ni crea una conexión con un proveedor.
TLS y DTLS cifran la conexión de la aplicación hasta su destino. TCP y UDP simples conservan el protocolo en claro de la aplicación; el cifrado de transporte de URnetwork hasta un proveedor no convierte ese protocolo en TLS hasta el destino.
Redes y nombres de host
Conecta con un host:port usando una de estas redes:
| Red | Comportamiento |
|---|---|
tcp | TCP con Happy Eyeballs IPv4/IPv6 para un nombre de host |
tcp4, tcp6 | TCP restringido a esa familia de direcciones |
udp | UDP; un nombre de host de doble familia elige su par poniendo a competir el primer datagrama/respuesta |
udp4, udp6 | UDP restringido a esa familia de direcciones |
Pon entre corchetes los literales IPv6, por ejemplo [2001:db8::10]:443. La resolución de nombres de host usa el resolvedor de sockets y la ruta de paquetes del Device. Cuando no hay un proveedor disponible, no recurre a resolver ni a abrir el destino directamente a través del host.
El Happy Eyeballs de TCP pone a competir los intentos de conexión. Los dialers TLS/DTLS eligen una familia después de que su handshake seguro tenga éxito. Los nombres de familia explícitos y las direcciones literales se saltan la carrera de doble familia.
UDP: posible entrega duplicada
UDP no tiene handshake de conexión. Para udp con registros A y AAAA, la primera escritura va a IPv6, y después a IPv4 tras 250 ms sin respuesta. Un fallo inmediato de escritura en IPv6 adelanta ese paso. El datagrama inicial de la aplicación puede llegar a ambas direcciones. La primera respuesta selecciona el par, y las escrituras posteriores van solo a ese par.
Usa IDs de petición u otro mecanismo de gestión de duplicados a nivel de aplicación cuando la entrega duplicada importe. Una primera escritura con éxito no demuestra la entrega ni selecciona un par. Si el servidor no responde nunca, las escrituras posteriores esperan a la selección hasta su plazo o hasta el cierre. Para protocolos de solo envío, usa udp4, udp6 o una IP literal. Una respuesta de cero bytes es una respuesta válida.
Cada escritura UDP es un datagrama. Cada lectura consume un datagrama; un búfer de lectura pequeño descarta los bytes restantes. Un datagrama vacío son datos, no EOF. Mantén los mensajes dentro de los límites del protocolo de destino y de la ruta.
Go
DeviceLocal y DeviceRemote ofrecen Dial, DialContext, DialTls y DialTlsContext. Los métodos de conexión ordinarios usan las mismas firmas que el net.Dialer de Go y devuelven una conexión compatible con net.Conn.
// 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"))Un cliente HTTP existente puede usar el Device directamente:
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.Para cifrar directamente, llama a device.DialTlsContext(ctx, "tcp", "example.com:443", nil). TCP usa TLS; UDP usa DTLS 1.2. Una configuración TLS nil usa la verificación de certificados normal. El nombre de host original aporta el nombre de servidor por defecto. DTLS admite una superficie de configuración más reducida que el TLS de Go y rechaza las opciones de seguridad que no admite.
Las lecturas y escrituras pueden devolver datos parciales junto con un error; procesa los bytes devueltos. El contexto del dial controla el establecimiento de la conexión, no la vida de una conexión ya establecida. Fija plazos absolutos para la E/S posterior y usa time.Time{} para borrarlos. Cierra la conexión al terminar. El límite por defecto para el establecimiento/handshake seguro es de 30 segundos, y un plazo anterior del llamador lo acorta.
JavaScript y TypeScript
Los envoltorios de Device del SDK ofrecen los métodos dial y dialTls, basados en Promise. Una página de navegador usa un Device remoto configurado que admite sockets. El SDK expone la conexión remota a través de WASM; no requiere soporte nativo de Direct Sockets en el navegador ni empaquetado como 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() devuelve un Uint8Array, o null en EOF. Un array vacío es un datagrama UDP válido. readable y writable ofrecen adaptadores de Web Streams; en cada dirección, elige o los métodos directos o los adaptadores. Cerrar el stream TCP envía un FIN en el lado de escritura cuando se admite. Un close() explícito cierra la conexión entera.
Usa un AbortSignal para cancelar la apertura. Los sockets ya establecidos usan plazos y cierre. Los métodos de plazo aceptan milisegundos de época, un Date o null para borrarlo. Un error de escritura parcial incluye bytesWritten; los datos de una lectura parcial se devuelven antes que el error que los acompaña, que llega en la siguiente lectura directa. El tráfico del socket se detiene cuando se desconecta el servicio remoto al que pertenece; no se reproduce tras la reconexión.
API de Direct Sockets
Usa las firmas de los constructores de Direct Sockets con un Device de UR:
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;
}Para UDP, construye new UDPSocket({remoteAddress: "echo.example", remotePort: 9001}). Espera a opened, luego escribe {data: new Uint8Array([1, 2, 3])} y lee value.data. Cada objeto es un datagrama, incluido un datagrama de cero bytes. Los mensajes de UDP conectado omiten los campos de dirección remota y rechazan que se cambie el destino por mensaje.
La fábrica exportada createDirectSockets(device) también devuelve estos constructores. Ambas interfaces tienen las promesas opened y closed y un close() asíncrono. TCP admite lectores por defecto y BYOB, y escrituras de BufferSource. Cerrar su stream de escritura envía FIN mientras las lecturas siguen disponibles. Cancela/aborta las operaciones pendientes y libera los bloqueos de lector/escritor antes de cerrar un socket; si no, close() se rechaza con InvalidStateError. Los fallos de red se rechazan con NetworkError.
La API nativa de Chrome está disponible para las Isolated Web Apps. La implementación del SDK funciona en navegadores corrientes y en Node sobre el Device configurado, sin paquete IWA ni permiso nativo de Direct Sockets. No reemplaza los globales del navegador. Consulta la documentación de Chrome y la propuesta de Direct Sockets.
Esta versión implementa TCP saliente y UDP conectado. Usa dnsQueryType: "ipv4" o "ipv6" para restringir la resolución; si lo omites, se conserva el Happy Eyeballs del Device. El UDP enlazado (bound), la multidifusión, los listeners y el ajuste por socket de búfer/no-delay/keep-alive no están disponibles, y las peticiones válidas de esas funciones fallan con NotSupportedError. Es un perfil de compatibilidad de cliente, no la API completa del navegador.
Con nombres UDP de doble familia, opened se resuelve antes de enviar. Sus campos de endpoint describen al principio el primer candidato y se actualizan tras consumir la primera respuesta. El datagrama inicial puede llegar a ambas direcciones. Elige una IP literal o una familia DNS cuando necesites un endpoint fijo desde la apertura. Los ejemplos usan un temporizador para cancelar la E/S de streams estancada; la API Conn, aparte, también ofrece plazos.
Los constructores de Direct Sockets abren conexiones TCP/UDP simples. Usa dialTls para TLS/DTLS. Los ejemplos de JavaScript para Node/navegador y el ejemplo de TypeScript, todos ejecutables, incluyen eco TCP/UDP, tiempos de espera, limpieza e integración con bibliotecas HTTP.
Bindings nativos y plataformas admitidas
| Binding | Superficie de sockets y plataforma |
|---|---|
| Go | Comportamiento de net.Conn en los targets de Go que admite el SDK |
| Kotlin/Java en Android | OpenSocket/Socket portables en el AAR; Android API 24+ con las ABI que se distribuyen |
| Swift de Apple | OpenSocket/Socket portables en el XCFramework; iOS 16+ y macOS 13.5+ con los slices de dispositivo/simulador que se distribuyen |
| C/C++ y otros clientes FFI | ABI de C para Windows 10+ y Linux glibc 2.35+ en amd64/arm64; compilaciones de host en macOS para desarrollo |
| JS/TS en navegador y Node | WASM, Conn y Web Streams de Direct Sockets, más un endpoint RPC de Device con capacidad de sockets disponible |
En móvil, los llamadores usan OpenSocket(network, address, timeoutMillis, tlsOptions). Unas opciones TLS nil piden una conexión simple; una configuración no nil pide TLS/DTLS. Socket.Read devuelve un resultado con Data y Eof; los métodos de plazo toman milisegundos de época, con cero para borrarlo. Usa un hilo de trabajo o un dispatcher de corrutinas adecuado para las operaciones bloqueantes.
En C, los llamadores usan urnet_device_dial / urnet_device_dial_tls, seguidos de urnet_conn_read, urnet_conn_write y las funciones de plazo/cierre. La lectura devuelve un recuento de bytes y un flag de EOF aparte. Consume los datos de inmediato; no es una consulta del tamaño del búfer de salida. Procesa los recuentos parciales de bytes incluso cuando se devuelve una cadena de error. Libera las cadenas de error/dirección con urnet_free_string, y libera el handle de la conexión con urnet_release, que además la cierra.
Por ahora, el SDK ofrece conexiones de cliente. Los sockets de servidor/listener llegarán como una adición aparte, con una semántica explícita de alcanzabilidad y propiedad. Consulta el recorrido del SDK para el modelo de bindings/compilación, y Primeros pasos para configurar el Device.