01 · Punto de partida
El límite de preguntar
En el tema 20 vimos que el polling tiene un costo: cuanto más seguido el dispositivo pregunta, menos tarda en enterarse de una orden, y más energía y datos gasta. Con una consulta cada 60 segundos, una orden llega en promedio a los 30 s; con una cada 10 s, a los 5 s, pero la batería dura dos semanas. Y en cualquier caso, casi todas las consultas vuelven vacías: «no hay nada para vos».
El problema de fondo es que HTTP no permite que el servidor inicie la comunicación. Un WebSocket lo resuelve cambiando el modelo: después de un saludo inicial, la conexión TCP queda abierta y deja de ser un pedido y una respuesta para convertirse en un canal bidireccional. El servidor puede empujar un mensaje en el momento en que lo tiene, y el dispositivo puede enviar el suyo sin esperar turno. La demora baja de segundos a décimas de segundo, y el tráfico, de megabytes por día a unos pocos kilobytes.
Este tema cierra el bloque de HTTP. El siguiente trata MQTT, que comparte la idea de una conexión persistente y agrega mucho más.
02 · Cómo se establece
De HTTP a WebSocket
Un WebSocket nace como una petición HTTP común. El cliente pide «cambiar de protocolo» con dos cabeceras especiales (Upgrade: websocket y Connection: Upgrade) y una clave aleatoria. Si el servidor acepta, responde con el código 101 Switching Protocols y una cabecera que prueba que entendió. A partir de ahí, la misma conexión TCP deja de hablar HTTP y pasa a intercambiar tramas de WebSocket.
El servidor no puede responder «101» a cualquier pedido: calcula la cabecera Sec-WebSocket-Accept combinando la clave del cliente con una constante fija del estándar y aplicando un resumen criptográfico (el código de este tema lo hace). No es seguridad, sino una prueba de que el servidor entiende WebSocket y de que la respuesta no es la de una caché antigua. La dirección usa los esquemas ws:// (sin cifrar) y wss:// (sobre TLS, equivalente a HTTPS); en un dispositivo real, siempre wss://.
Como el saludo es HTTP, atraviesa los mismos firewalls y proxies que cualquier otra conexión web (puerto 443). Es una de las razones de su popularidad.
03 · Los mensajes
Las tramas y su sobre
Una vez abierta la conexión, los datos viajan en tramas. A diferencia de HTTP, donde cada mensaje arrastra cientos de bytes de cabeceras, la trama de un WebSocket tiene un sobre mínimo: 2 bytes para cargas de hasta 125 bytes, 4 bytes hasta 64 KB y 10 bytes para más. Hay un detalle: las tramas que envía el cliente (el dispositivo) llevan además una máscara de 4 bytes, un requisito del estándar para evitar ciertos ataques a intermediarios. Así, un mensaje corto del servidor al dispositivo suma 2 bytes de sobre, y uno del dispositivo al servidor, 6.
| Tipo | Para qué sirve | Uso en IoT |
|---|---|---|
| Texto | Un mensaje en UTF-8 | JSON con órdenes, estado y lecturas |
| Binario | Un mensaje de bytes | Formatos compactos (CBOR, binario propio; tema 12), audio, firmware |
| Ping | «¿Seguís ahí?» | Mantener viva la conexión y detectar cortes |
| Pong | La respuesta automática al ping | Confirmar que el otro extremo vive |
| Cierre | Termina la conexión de forma ordenada, con un código | Apagar el canal sabiendo por qué |
| Continuación | Parte de un mensaje fragmentado | Mensajes más grandes que un buffer |
Un WebSocket entrega mensajes completos y en orden mientras la conexión viva (hereda de TCP el orden y la entrega), y no deja que el programador se ocupe de dónde termina uno y empieza el siguiente, como sí ocurre con un socket TCP crudo. Lo que no hace es ocuparse de qué mensajes se perdieron si la conexión se cae: eso es responsabilidad de la aplicación, como se ve a continuación.
04 · Resistencia
Mantener viva la conexión
Una conexión abierta durante horas o días tiene problemas que una petición corta no conoce. Hay que gestionarlos desde el diseño.
Ping y pong
El NAT del router olvida las conversaciones inactivas (tema 17), a veces en 30 a 60 segundos, y una conexión que no lleva tráfico queda cortada sin que ninguno de los dos extremos lo sepa. La defensa es el ping periódico: cada cierto intervalo, menor que el tiempo de olvido del NAT, uno de los lados envía un ping y el otro contesta con un pong. Sirve para dos cosas: mantener abierta la entrada del NAT, y detectar cuándo el otro lado ya no está (si el pong no llega en unos segundos, la conexión se da por muerta). Con un ping cada 30 s, la conexión cuesta unos 100 bytes cada 30 segundos: 288 KB por día.
Reconexión
Tarde o temprano la conexión se cae: se cortó el Wi-Fi, reinició el servidor o venció una sesión. El cliente debe reconectar solo, con la misma política de los temas 5 y 18: espera creciente con retardo aleatorio, para no provocar una avalancha cuando miles de dispositivos pierden el servidor a la vez.
Lo que se pierde
Una caída tiene una consecuencia sutil: los mensajes enviados mientras no hay conexión se pierden, y los que estaban en tránsito, quizás también. Si el servidor empujó una orden a un dispositivo que justo se había desconectado, la orden no llegó, y WebSocket no se lo avisa. Por eso un diseño robusto agrega encima del canal sus propias garantías:
- Números de secuencia en los mensajes importantes, y confirmaciones de recibo (ack) por parte del dispositivo.
- Órdenes pendientes en el servidor: el servidor guarda cada orden hasta que el dispositivo confirma, y la reenvía al reconectar.
- Órdenes idempotentes y con vencimiento (tema 11): un reenvío no duplica la acción y una orden vieja se descarta.
- Al reconectar, resincronizar: el dispositivo informa su estado actual y la última secuencia que recibió, y el servidor le manda lo que falta.
Esto es, justamente, lo que MQTT resuelve de fábrica con sus niveles de calidad de servicio y sus sesiones persistentes; con WebSocket crudo hay que construirlo.
#include <WebSocketsClient.h> // biblioteca arduinoWebSockets
WebSocketsClient ws;
uint32_t ultimaSecuencia = 0; // última orden procesada (guardar en memoria no volátil)
void alEvento(WStype_t tipo, uint8_t *datos, size_t largo) {
switch (tipo) {
case WStype_CONNECTED:
Serial.println("WebSocket abierto");
ws.sendTXT(String("{\"hola\":\"c07\",\"ultima\":") + ultimaSecuencia + "}"); // resincronizar
break;
case WStype_DISCONNECTED:
Serial.println("WebSocket cerrado"); // la biblioteca reintenta sola (ver setReconnectInterval)
break;
case WStype_TEXT:
procesarOrden((const char *)datos, largo); // validar, ejecutar, confirmar
break;
default:
break;
}
}
void setup() {
// ... conectar a Wi-Fi ...
ws.beginSSL("datos.ejemplo.com", 443, "/ws"); // wss://, siempre cifrado
ws.onEvent(alEvento);
ws.setExtraHeaders("Authorization: Bearer ..."); // el token va en el saludo, no en la URL
ws.setReconnectInterval(5000); // espera entre reintentos
ws.enableHeartbeat(30000, 3000, 2); // ping cada 30 s; si no hay pong en 3 s, 2 veces, se da por caída
}
void loop() {
ws.loop(); // procesa tramas, pings y reconexiones
}
El fragmento muestra el patrón completo: se abre la conexión cifrada, el saludo lleva el token, el heartbeat detecta cortes, y al abrir (o reabrir) la conexión el dispositivo informa cuál fue la última orden que procesó, para que el servidor reenvíe las pendientes. Los nombres de las funciones corresponden a una biblioteca popular y pueden variar entre versiones; verificalos contra la documentación de la tuya.
05 · Defensa
Seguridad
Una conexión abierta durante días es un canal privilegiado: por ella llegan órdenes al dispositivo. Las reglas de siempre se aplican con más razón:
- Siempre
wss://, con verificación del certificado del servidor. Un WebSocket sin cifrar deja órdenes y credenciales a la vista. - Autenticación en el saludo. El token viaja en una cabecera del saludo (
Authorization), nunca en la URL (que se registra en los logs, tema 20). Los navegadores no permiten poner cabeceras propias en un WebSocket, y para ellos se usan otras técnicas (un primer mensaje de autenticación, o una credencial de corta duración); un dispositivo sí puede enviar cabeceras. - El servidor verifica el origen de cada orden y que el dispositivo solo reciba mensajes dirigidos a él. Un canal por dispositivo, nunca uno compartido.
- Validar cada mensaje. Que sea JSON válido, de un tamaño razonable, con los campos y rangos esperados (tema 21) y vigente (fecha y número de secuencia).
- Límites: tamaño máximo de mensaje, ritmo máximo de mensajes por segundo, y cantidad de conexiones por cuenta, para que una conexión comprometida no sature al servidor o al dispositivo.
06 · Decisión
Cuándo usarlo
El WebSocket es la herramienta correcta cuando se necesita una latencia baja en ambos sentidos y la conexión puede permanecer abierta. No siempre se dan las dos condiciones en un dispositivo.
| Forma | Demora | Consumo | Cuándo conviene |
|---|---|---|---|
| Polling con conexión nueva | Mitad del intervalo (segundos a minutos) | Bajo si el intervalo es largo | Dispositivos con batería; órdenes poco urgentes |
| Respuesta del POST con órdenes (tema 20) | Hasta el próximo envío | El más bajo | Dispositivos con batería que ya envían periódicamente |
| WebSocket | Décimas de segundo | Radio atenta: cientos de mAh por día | Dispositivos con alimentación eléctrica; paneles en navegadores |
| MQTT (bloque 5) | Décimas de segundo | Igual que WebSocket, con ahorros por protocolo más liviano | Flotas, publicación y suscripción, garantías de entrega |
| Eventos del servidor (SSE) | Décimas de segundo, solo servidor → cliente | Radio atenta | Paneles que solo reciben |
En la práctica, el lugar donde más se usan los WebSockets en IoT no es el dispositivo sino el navegador del usuario: un panel de control que muestra las lecturas en vivo, y que recibe desde la nube cada dato apenas llega. Muchas plataformas ofrecen MQTT para los dispositivos y WebSocket (o MQTT sobre WebSocket) para los navegadores. En el dispositivo, el WebSocket aparece cuando hay alimentación eléctrica y se necesita comandar con baja demora: una cerradura, un controlador de iluminación, un panel de estado.
Con batería, la regla es otra: una conexión abierta mantiene la radio atenta (unos 20 mA, 480 mAh por día, cuatro días de autonomía en el modelo del tema 14), y la mejor opción es la respuesta del POST o un polling espaciado. Más adelante veremos que algunos módulos celulares y de bajo consumo reducen mucho ese costo con modos de ahorro propios, pero a cambio de más demora.
07 · Analogía con programación
Medir el sobre y el costo en Python
El programa tiene dos partes. La primera implementa el cálculo de la cabecera Sec-WebSocket-Accept (resumen SHA-1 de la clave más la constante del estándar, en base64) y comprueba el ejemplo oficial del estándar. También arma tramas de texto reales con la máscara del cliente y mide su sobre. La segunda compara el costo de recibir órdenes con consultas cada 10 s, 60 s y 5 minutos (conexión nueva en cada una) y con un WebSocket abierto con un ping cada 30 s, con 12 mensajes del servidor por hora: la demora media, los datos por día, los mAh por día y la autonomía de una batería de 2000 mAh.
Python en tu navegador. Los bloques son editables: cambiá los valores y presioná «Ejecutar Python». La primera vez tarda unos segundos en cargar.
import base64
import hashlib
import struct
# ---------- Parte 1: el saludo y el formato de los mensajes de un WebSocket ----------
GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" # constante fija definida por el protocolo (RFC 6455)
def clave_de_aceptacion(clave_cliente):
"""El servidor prueba que entendió el protocolo devolviendo esto en Sec-WebSocket-Accept."""
return base64.b64encode(hashlib.sha1((clave_cliente + GUID).encode()).digest()).decode()
def trama(carga, desde_cliente):
"""Arma una trama de texto: 2 bytes de cabecera (más 4 de máscara si la envía el cliente) y la carga."""
datos = carga.encode()
cabecera = bytes([0x81, len(datos) | (0x80 if desde_cliente else 0)]) # 0x81 = último fragmento, texto
if desde_cliente:
mascara = b"\x12\x34\x56\x78"
return cabecera + mascara + bytes(b ^ mascara[i % 4] for i, b in enumerate(datos))
return cabecera + datos
print("Sec-WebSocket-Accept para la clave de ejemplo del estándar:", clave_de_aceptacion("dGhlIHNhbXBsZSBub25jZQ=="))
mensaje = '{"cmd":"abrir","min":10}'
for origen in (False, True):
t = trama(mensaje, origen)
print(f"{'cliente → servidor' if origen else 'servidor → cliente'}: carga de {len(mensaje)} bytes, trama de {len(t)} bytes (sobre de {len(t) - len(mensaje)} bytes)")
# ---------- Parte 2: polling o conexión persistente ----------
BATERIA_MAH = 2000
SUENO_MAH_DIA = 0.24
MAH_POR_CONSULTA = 100 * 0.6 / 3600 # conexión nueva en cada consulta
BYTES_POR_CONSULTA = 4700 + 570 # apretón de manos más petición y respuesta
RADIO_ATENTA_MAH_DIA = 480 # conexión abierta: 20 mA durante 24 h
RTT_S = 0.1
BYTES_APRETON_WS = 5100 # TCP, TLS y el saludo de actualización a WebSocket
BYTES_PING = 100 # ping y pong con los encabezados de TCP e IP
BYTES_MENSAJE_WS = 2 + 40 + 40 # trama del servidor, 40 bytes de carga y encabezados de TCP e IP
def evaluar(metodo, mensajes_hora, ping_s=30):
if metodo == "websocket":
bytes_dia = BYTES_APRETON_WS + (86400 / ping_s) * BYTES_PING + mensajes_hora * 24 * BYTES_MENSAJE_WS
mah = RADIO_ATENTA_MAH_DIA
latencia = RTT_S / 2
else:
consultas = 86400 / metodo # metodo = segundos entre consultas
bytes_dia = consultas * BYTES_POR_CONSULTA
mah = SUENO_MAH_DIA + consultas * MAH_POR_CONSULTA
latencia = metodo / 2
return latencia, bytes_dia, mah, BATERIA_MAH / mah
print()
print("método mensajes/h demora media datos por día mAh/día batería")
for mensajes in (12,):
for metodo in (10, 60, 300, "websocket"):
lat, b, mah, dias = evaluar(metodo, mensajes)
nombre = "WebSocket" if metodo == "websocket" else f"consulta cada {metodo} s"
bat = f"{dias / 365:.1f} años" if dias >= 365 else f"{dias:.0f} días"
print(f"{nombre:<18} {mensajes:>9} {lat:>10.2f} s {b / 1e6:>12.2f} MB {mah:>10.2f} {bat}")
Resultado con los valores iniciales. Para la clave de ejemplo del estándar (dGhlIHNhbXBsZSBub25jZQ==) el servidor devuelve s3pPLMBiTxaQ9kYGzzhZRbK+xOo=, que es el valor que publica el estándar. Un mensaje de 24 bytes ocupa 26 bytes en una trama del servidor al dispositivo (2 bytes de sobre) y 30 bytes en una del dispositivo al servidor (6 bytes, por la máscara). En el costo: consultar cada 10 s da una demora media de 5 s, 45,53 MB por día, 144,24 mAh y 14 días de batería; cada 60 s, 30 s, 7,59 MB, 24,24 mAh y 83 días; cada 5 minutos, 150 s, 1,52 MB, 5,04 mAh y 1,1 años; y el WebSocket, 0,05 s de demora, 0,32 MB por día (incluidos 288 KB de pings), 480 mAh y 4 días.
Tres conclusiones del modelo. Una: el sobre de un WebSocket es de 2 a 6 bytes, frente a los cientos de HTTP: por eso 12 mensajes por hora cuestan menos de 1 KB por día de carga útil. Otra: el WebSocket es 100 veces más rápido y 140 veces más liviano en datos que la consulta cada 10 s (0,05 s contra 5 s; 0,32 MB contra 45,5 MB). Y la tercera, que mata la idea para equipos con pila: cuesta 480 mAh por día, 20 veces el gasto de la consulta cada minuto.
08 · Exploración interactiva
Preguntar o mantener abierto, de extremo a extremo
Este laboratorio ejecuta el mismo modelo del código anterior. Elegí cómo recibe el dispositivo las órdenes, si funciona con red eléctrica o con batería, cuántos mensajes recibe por hora y qué demora máxima admite una orden. Las barras comparan los cuatro métodos en datos por día (escala logarítmica), con la demora máxima y, si hay batería, la duración. Los costos son valores didácticos.
Recibir órdenes del servidor
Elegí los parámetros y presioná «Calcular».
Recorrido guiado
- Con los valores iniciales (WebSocket, red eléctrica, 12 mensajes por hora, 5 s), calculá. 50 ms de demora, 0,32 MB por día y «Cumple». Con alimentación eléctrica, el consumo de la radio atenta no importa.
- Cambiá a Consulta cada 60 s: demora máxima de 60 s, 7,59 MB por día: «Demasiado lento» para la exigencia de 5 s. Subí la exigencia a 60 s y cumple, con 24 veces más datos que el WebSocket.
- Probá Consulta cada 10 s con exigencia de 5 s: sigue siendo «Demasiado lento» (hasta 10 s) y mueve 45,5 MB por día. Para llegar a 0,5 s por polling harían falta 2 consultas por segundo, lo cual es impracticable.
- Cambiá la alimentación a Batería con WebSocket: 480 mAh por día, 4 días de duración y «Agota la batería». La demora excelente no sirve si el equipo se apaga en cuatro días.
- Con batería, elegí Consulta cada 5 min y una exigencia de 10 min: 5,04 mAh por día, 1,1 años y «Cumple». Es el diseño correcto para órdenes poco urgentes con pila.
- Con WebSocket, subí a 120 mensajes por hora en red eléctrica: 0,53 MB por día, apenas más que con 12. Con muchos mensajes, el WebSocket gana todavía más, porque cada uno cuesta unas decenas de bytes.
Desafío: el punto de cruce de datos
Con una consulta cada 60 segundos y conexión nueva, el dispositivo mueve 7,59 MB por día aunque no haya ninguna orden: 1440 consultas de 5270 bytes. El WebSocket, con ping cada 30 s, mueve 0,32 MB al día con 12 mensajes por hora, y crece unos 2 KB por cada mensaje por hora adicional. Para que el WebSocket mueva tantos datos como el polling de 60 s, haría falta recibir unos 3700 mensajes por hora, algo muy raro. En datos, el WebSocket gana casi siempre. Lo que lo limita no es el tráfico sino la energía: la radio atenta cuesta 480 mAh por día, contra 24 mAh del polling de 60 s con conexión nueva. El WebSocket ahorra datos y demora; el polling ahorra batería. Se elige según qué recurso falta.
09 · Método de trabajo
Lista de verificación de un canal en tiempo real
- Decidí si lo necesitás: ¿qué demora máxima admiten las órdenes y qué fuente de energía tiene el equipo? Con batería, probá primero la respuesta del POST o un polling espaciado.
wss://siempre, con verificación del certificado y el token en el saludo, no en la URL.- Ping y pong con un intervalo menor que el olvido del NAT, y un tiempo máximo para el pong.
- Reconexión con espera creciente y retardo aleatorio.
- Secuencia y confirmaciones en los mensajes importantes; el servidor guarda las órdenes pendientes y las reenvía al reconectar.
- Resincronizar al abrir: el dispositivo informa su estado y la última secuencia procesada.
- Órdenes idempotentes y con vencimiento, validadas campo por campo.
- Límites de tamaño y de ritmo de mensajes, y una conexión por dispositivo.
- Plan de contingencia: si el WebSocket no abre, el dispositivo debe poder seguir funcionando con consulta espaciada.
- Pruebas: cortar el Wi-Fi, reiniciar el servidor, dejar la conexión inactiva horas (para ver si el NAT la cierra), mandar mensajes enormes y mensajes inválidos.
Un experimento revelador: abrí un WebSocket sin pings y dejalo inactivo. En muchas redes, a los pocos minutos queda cortado sin avisar: la próxima orden se pierde. Con el ping activado, vive indefinidamente.
10 · Comprensión
Confusiones frecuentes
«Un WebSocket garantiza que no se pierden mensajes»
Garantiza orden y entrega mientras la conexión vive. Si se cae, los mensajes en tránsito o enviados después se pierden, y la aplicación no se entera. Hay que sumar secuencia, confirmaciones y reenvío de las pendientes.
«Como el WebSocket usa menos datos, también gasta menos batería»
Usa menos datos, pero mantiene la radio atenta todo el tiempo: unos 480 mAh por día, mucho más que un polling espaciado. Con batería suele ser mucho peor.
«El servidor puede conectarse al dispositivo con un WebSocket»
No: es el dispositivo el que abre la conexión (saliente, atravesando el NAT) y después el servidor puede empujar mensajes por esa conexión. El WebSocket no cambia quién inicia la conversación, sino lo que ocurre después.
«Con ping cada 5 minutos es suficiente, ahorra datos»
Si el NAT olvida las conexiones inactivas en 60 segundos, la conexión muere entre ping y ping. El intervalo debe ser menor que el olvido del NAT, o se vive reconectando.
«Puedo poner el token en la URL del WebSocket, es lo más fácil»
La URL se guarda en registros de servidores y proxies. El token va en una cabecera del saludo (un dispositivo puede hacerlo) o en el primer mensaje.
«WebSocket reemplaza a HTTP»
Se complementan. HTTP sigue siendo lo mejor para pedidos puntuales y APIs; WebSocket, para canales de larga duración. Un dispositivo puede usar ambos: HTTP para enviar y un canal persistente solo si necesita escuchar con baja demora.
11 · Práctica guiada
Predecí antes de comprobar
1. Tamaño de una trama
Un mensaje de texto de 24 bytes, ¿cuántos bytes ocupa en una trama del servidor al dispositivo y en una del dispositivo al servidor?
Ver solución
Servidor → dispositivo: 2 bytes de sobre + 24 = 26 bytes. Dispositivo → servidor: 2 + 4 de máscara + 24 = 30 bytes. Comparado con los cientos de bytes de cabeceras de una petición HTTP, el sobre es mínimo.
2. El costo de los pings
Un ping y su pong suman unos 100 bytes con los encabezados de red. Con un ping cada 30 s, ¿cuántos bytes por día cuesta mantener la conexión?
Ver solución
86.400 / 30 = 2880 pings por día × 100 bytes = 288.000 bytes, unos 288 KB. Con un ping cada 60 s serían 144 KB, siempre que el NAT no olvide la conexión antes.
3. Demora
Un dispositivo consulta cada 60 s. ¿Cuál es la demora media y la máxima hasta una orden? ¿Y con un WebSocket con RTT de 100 ms?
Ver solución
Con polling: media 30 s, máxima 60 s. Con WebSocket: la orden viaja en medio viaje de ida y vuelta, unos 50 ms. Seiscientas veces menos demora.
4. El NAT que olvida
El NAT de una red celular olvida las conexiones inactivas a los 60 segundos. ¿Cada cuánto debe ir el ping?
Ver solución
Menos de 60 s, con margen: por ejemplo cada 30 s (o 45 s). Si fuera cada 90 s, el NAT cerraría la entrada antes del siguiente ping y la conexión se perdería sin aviso.
5. Una orden perdida
El servidor envía «abrir 10 minutos» por el WebSocket, pero el dispositivo se había desconectado hacía 5 segundos sin que el servidor lo notara. ¿Qué pasa y cómo se evita?
Ver solución
La orden se pierde: el servidor cree que la envió, el dispositivo nunca la recibió. Se evita con una confirmación: el servidor conserva la orden como pendiente hasta que el dispositivo responda con un ack, y la reenvía al reconectar (con un vencimiento, para no ejecutar una orden vieja).
6. Batería o red
Un WebSocket abierto gasta 20 mA continuos. ¿Cuántos mAh por día y cuánto dura una batería de 2000 mAh? ¿Para qué dispositivos entonces?
Ver solución
20 mA × 24 h = 480 mAh por día; 2000 / 480 ≈ 4 días. Solo sirve para dispositivos con alimentación eléctrica (una cerradura de red, un controlador de iluminación) o para el navegador del usuario. Con batería, un polling espaciado o la respuesta del POST.
12 · Síntesis
Ideas para recordar
- HTTP no permite que el servidor inicie la comunicación; un WebSocket convierte una conexión HTTP en un canal bidireccional persistente por el que ambos hablan cuando quieren.
- Nace con un saludo HTTP (
Upgrade: websocket) al que el servidor responde101 Switching Protocols; en un dispositivo se usa siemprewss://. - Las tramas tienen un sobre de 2 bytes (6 si las envía el cliente por la máscara), frente a cientos de bytes de cabeceras HTTP.
- Mientras la conexión vive, los mensajes llegan completos y en orden; si se cae, lo enviado en ese lapso se pierde y la aplicación debe recuperarlo con secuencia, confirmaciones y reenvío.
- El ping y el pong mantienen abierta la entrada del NAT y detectan cortes; el intervalo debe ser menor que el olvido del NAT.
- La reconexión usa espera creciente y retardo aleatorio, y al abrir el dispositivo informa su estado y la última orden procesada.
- El token va en el saludo, nunca en la URL; se valida cada mensaje y se limitan el tamaño y el ritmo.
- Frente al polling, el WebSocket baja la demora de segundos a décimas y los datos entre 10 y 100 veces, pero mantiene la radio atenta: 480 mAh por día, solo viable con alimentación eléctrica.
- Con batería conviene llevar las órdenes en la respuesta del POST o consultar con un intervalo largo; el WebSocket brilla en paneles de navegador y en equipos enchufados.
¿Listo para el bloque 5?
Antes de avanzar, decidí para cada dispositivo de tu proyecto cómo recibe las órdenes: respuesta del POST, polling o canal persistente. Calculá la demora máxima que admite, el consumo de cada alternativa y si hay alimentación eléctrica. Anotá qué pasa con una orden enviada mientras el dispositivo está desconectado.
El siguiente bloque trata de MQTT, el protocolo pensado específicamente para esta situación: conexión persistente, publicación y suscripción por tópicos, niveles de garantía de entrega, sesiones que sobreviven a las caídas y mensajes de última voluntad. Empezamos con el tema 25, qué es MQTT.