Fundamentos de MQTT

¿Cómo funciona MQTT? Brokers, clientes y mensajes explicados

Una explicación paso a paso de cómo funciona MQTT, desde abrir una conexión TCP hasta CONNECT, SUBSCRIBE, PUBLISH, keep alive y la desconexión, con una traza que puedes reproducir en un broker público.

Diagrama de cómo funciona MQTT con clientes que envían paquetes CONNECT, SUBSCRIBE y PUBLISH a través de un broker central
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

¿Cómo funciona MQTT? En pocas palabras, los clientes abren una única conexión de larga duración con un broker, declaran qué topics les interesan y el broker reenvía cada mensaje publicado a los suscriptores que coinciden. En este artículo seguirás ese proceso paquete a paquete, desde la conexión TCP pasando por CONNECT, SUBSCRIBE, PUBLISH, keep alive y la desconexión, y reproducirás tú mismo toda la traza en un servidor MQTT público gratuito.

Los tres roles: publicador, suscriptor y broker

MQTT solo tiene dos tipos de participantes: clientes y brokers. Un cliente puede publicar, suscribirse o ambas cosas. El broker se sitúa en medio, recibe cada mensaje y decide quién lo recibe.

  • Los publicadores envían mensajes a un topic, una cadena como plant1/line2/temperature. No saben ni les importa quién los recibe.
  • Los suscriptores indican al broker qué topics, o patrones de topics, quieren. No saben quién envía.
  • El broker autentica a los clientes, lleva el registro de suscripciones y sesiones y enruta cada mensaje a todos los suscriptores que coinciden.

Este desacoplamiento es el corazón del diseño. Un sensor no necesita la dirección IP de un panel, los dos no necesitan estar conectados al mismo tiempo si las sesiones son persistentes, y añadir un quinto consumidor no exige ningún cambio en el sensor. Para saber más sobre el trabajo del broker, consulta qué hace un broker MQTT, y para el patrón en sí, el modelo de publicación/suscripción de MQTT.

Paso 1: abrir una conexión de red

MQTT funciona sobre un flujo de bytes fiable y ordenado, normalmente TCP. El cliente abre una conexión TCP con el broker, en el puerto 1883 para MQTT sin cifrar o en el 8883 para MQTT sobre TLS. Los navegadores, que no pueden abrir sockets TCP crudos, transportan MQTT dentro de un WebSocket (en ConnectMQ, en el 8083 o el 8084 con la ruta /mqtt). Todavía no ha ocurrido nada específico de MQTT; esto es solo la tubería.

Con TLS, se produce entonces un handshake: el cliente comprueba el certificado del broker y ambos lados acuerdan las claves de cifrado. A partir de ahí, todos los paquetes MQTT van cifrados.

Paso 2: CONNECT y CONNACK

El primer paquete del cliente debe ser CONNECT. Contiene:

Campo Propósito
Nombre y nivel del protocolo MQTT y 4 (3.1.1) o 5 (5.0)
Client ID Identifica la sesión; debe ser único por conexión
Clean session / clean start Empezar de cero o reanudar una sesión almacenada
Keep alive Máximo de segundos entre paquetes del cliente
Usuario y contraseña Credenciales opcionales
Last Will Mensaje opcional que el broker publica si el cliente desaparece
Propiedades (MQTT 5) Caducidad de sesión, receive maximum, tamaño máximo de paquete y más

El broker valida todo esto y responde con CONNACK. En MQTT 5 incluye un código de motivo: 0x00 si todo fue bien, o un error como credenciales incorrectas, no autorizado o, en un broker con cuotas, 0x97 quota exceeded. También indica si se reanudó una sesión anterior (flag session present) y puede informar al cliente de los límites del servidor. Hasta que llega un CONNACK correcto, el cliente no debe enviar nada más.

Paso 3: SUBSCRIBE y SUBACK

Un cliente que quiere recibir mensajes envía SUBSCRIBE con uno o varios filtros de topic y un QoS solicitado para cada uno. Los filtros pueden incluir comodines: + coincide exactamente con un nivel y # coincide con todo lo que hay por debajo de un nivel. Por ejemplo, plant1/+/temperature coincide con plant1/line2/temperature, pero no con plant1/line2/motor/temperature.

El broker responde con SUBACK, indicando el QoS concedido (o un código de error) para cada filtro. El QoS concedido puede ser inferior al solicitado si el broker lo limita. Si existen retained messages en los topics que coinciden, el broker los envía de inmediato; así es como un panel nuevo conoce al instante el estado actual.

Paso 4: PUBLISH y los handshakes de QoS

Para enviar datos, un cliente envía PUBLISH con un nombre de topic, un payload (cualquier secuencia de bytes, a menudo JSON), un nivel de QoS y un flag retain. Lo que ocurre después depende del QoS:

  1. QoS 0, como máximo una vez. PUBLISH y listo. Sin confirmación; si la conexión se cae en mal momento, el mensaje se pierde.
  2. QoS 1, al menos una vez. El receptor responde con PUBACK. Si el emisor no lo recibe, reenvía con el flag de duplicado activado, así que el receptor puede ver el mensaje dos veces.
  3. QoS 2, exactamente una vez. Un intercambio en cuatro pasos: PUBLISH, PUBREC, PUBREL, PUBCOMP. Más lento, pero sin duplicados.

Estos handshakes ocurren salto a salto: una vez entre el publicador y el broker y, por separado, entre el broker y cada suscriptor. Después, el broker reenvía el mensaje a cada cliente cuyo filtro coincide, usando el menor entre el QoS de publicación y el QoS concedido a la suscripción. Los compromisos completos están en los niveles de QoS de MQTT explicados.

Con el flag retain activado, el broker además guarda el mensaje como último valor conocido de ese topic y se lo entrega a los futuros suscriptores.

Paso 5: keep alive con PINGREQ y PINGRESP

Aunque esté inactivo, un cliente debe seguir demostrando que está vivo dentro del intervalo de keep alive. Si no tiene nada que publicar, envía PINGREQ y el broker responde con PINGRESP. Si el broker no recibe nada durante aproximadamente una vez y media el periodo de keep alive, considera muerto al cliente, cierra la conexión y publica su Last Will, si se configuró uno. Así es como los paneles saben que un dispositivo se ha desconectado sin que nadie tenga que sondear.

Paso 6: DISCONNECT y sesiones

Un cierre limpio envía DISCONNECT, que indica al broker que no publique el Last Will. Lo que sobrevive depende de los ajustes de sesión: con clean start y sin caducidad de sesión, el broker olvida las suscripciones del cliente. Con una sesión persistente (caducidad de sesión de MQTT 5 mayor que cero), el broker conserva las suscripciones y pone en cola los mensajes QoS 1 y 2 hasta que el cliente vuelve o vence la caducidad.

Reproduce tú mismo la traza

Puedes observar todo el ciclo de vida en el servidor MQTT público gratuito en broker.connectmq.com, pensado para pruebas y no para datos de producción. Los clientes de Mosquitto imprimen cada paquete con -d. Elige primero un ID aleatorio único; aquí es q7m3x9.

# Terminal 1: suscriptor con salida de depuración
mosquitto_sub -h broker.connectmq.com -p 1883 -i sub-q7m3x9 -V mqttv5 -d \
  -t 'connectmq/demo/q7m3x9/#' -q 1

# Terminal 2: publicador con salida de depuración
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-q7m3x9 -V mqttv5 -d \
  -t 'connectmq/demo/q7m3x9/sensor/temp' -m '{"c":21.7}' -q 1

La salida del suscriptor tiene este aspecto (los detalles varían según la versión):

Client sub-q7m3x9 sending CONNECT
Client sub-q7m3x9 received CONNACK (0)
Client sub-q7m3x9 sending SUBSCRIBE (Mid: 1, Topic: connectmq/demo/q7m3x9/#, QoS: 1, Options: 0x00)
Client sub-q7m3x9 received SUBACK
Subscribed (mid: 1): 1
Client sub-q7m3x9 received PUBLISH (d0, q1, r0, m1, 'connectmq/demo/q7m3x9/sensor/temp', ... (10 bytes))
Client sub-q7m3x9 sending PUBACK (m1, rc0)
{"c":21.7}
Client sub-q7m3x9 sending PINGREQ
Client sub-q7m3x9 received PINGRESP

Y la del publicador:

Client pub-q7m3x9 sending CONNECT
Client pub-q7m3x9 received CONNACK (0)
Client pub-q7m3x9 sending PUBLISH (d0, q1, r0, m1, 'connectmq/demo/q7m3x9/sensor/temp', ... (10 bytes))
Client pub-q7m3x9 received PUBACK (Mid: 1, RC:0)
Client pub-q7m3x9 sending DISCONNECT

Lee los flags de la línea PUBLISH: d0 (no es un duplicado), q1 (QoS 1), r0 (no retenido), m1 (identificador de paquete 1). Prueba con -q 2 y verás PUBREC, PUBREL y PUBCOMP; añade -r al publicador, reinicia el suscriptor y el mensaje retenido llegará justo después de SUBACK. El área pública puede leerla cualquiera, así que envía solo datos de prueba.

El mismo flujo en Python

Las bibliotecas ocultan los paquetes tras callbacks, pero cada uno se corresponde con un paso de los anteriores.

import time
import uuid

import paho.mqtt.client as mqtt

PREFIX = f"connectmq/demo/{uuid.uuid4().hex[:6]}"


def on_connect(client, userdata, flags, reason_code, properties):   # CONNACK
    print("CONNACK:", reason_code)
    client.subscribe(f"{PREFIX}/#", qos=1)                           # SUBSCRIBE


def on_subscribe(client, userdata, mid, reason_codes, properties):  # SUBACK
    print("SUBACK:", [str(rc) for rc in reason_codes])
    client.publish(f"{PREFIX}/sensor/temp", '{"c":21.7}', qos=1)     # PUBLISH


def on_publish(client, userdata, mid, reason_code, properties):     # PUBACK
    print("PUBACK for mid", mid)


def on_message(client, userdata, msg):                               # PUBLISH entrante
    print("Message:", msg.topic, msg.payload.decode())


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id=f"trace-{uuid.uuid4().hex[:8]}",
                     protocol=mqtt.MQTTv5)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_publish = on_publish
client.on_message = on_message

client.connect("broker.connectmq.com", 1883, keepalive=30)          # TCP + CONNECT
client.loop_start()
time.sleep(5)
client.disconnect()                                                  # DISCONNECT
client.loop_stop()

Malentendidos habituales

  • "El broker guarda todos los mensajes." Solo los retained messages (uno por topic) y los mensajes en cola de las sesiones persistentes. MQTT no es una base de datos ni un log.
  • "Los topics hay que crearlos antes." No, los topics existen en el momento en que alguien publica o se suscribe.
  • "QoS 2 de extremo a extremo." El QoS se aplica por salto y se rebaja al nivel de la suscripción.
  • "Los client IDs se pueden compartir." Una segunda conexión con el mismo ID expulsa a la primera.
  • "MQTT usa UDP." El MQTT estándar necesita TCP u otro flujo fiable; MQTT-SN es la variante para UDP y redes similares.

Para profundizar, el tutorial de MQTT construye un proyecto completo, los paquetes de control de MQTT detalla cada tipo de paquete y las especificaciones oficiales están publicadas en mqtt.org.

Prueba MQTT en ConnectMQ

Experimenta libremente en broker.connectmq.com y, cuando quieras topics privados y autenticados, crea un broker Serverless gratuito en app.connectmq.com sin tarjeta de crédito. ConnectMQ es un broker MQTT en la nube compatible con MQTT 3.1.1 y 5.0, con un cliente en el navegador y un explorador de topics en vivo, para que puedas observar en tiempo real los flujos descritos aquí. Cuando pases a producción, funciona como un broker MQTT gestionado.

Preguntas frecuentes

¿Cómo funciona MQTT en pocas palabras?

Los dispositivos se conectan a un broker central, se suscriben a los topics que les interesan y publican mensajes en topics. El broker reenvía cada mensaje a todos los suscriptores que coinciden.

¿Los publicadores y los suscriptores se conectan directamente entre sí?

No. Cada cliente se conecta solo al broker, y por eso los dispositivos nunca necesitan las direcciones de los demás.

¿Qué ocurre si un suscriptor está desconectado cuando se publica un mensaje?

Con una sesión persistente y QoS 1 o 2, el broker pone el mensaje en cola hasta que el suscriptor se reconecta o la sesión caduca. Si no, el mensaje no se entrega a ese cliente, aunque un mensaje retenido le seguirá dando el último valor.

¿Qué puerto usa MQTT?

El 1883 para TCP sin cifrar y el 8883 para TLS. Los puertos WebSocket varían según el broker; ConnectMQ usa el 8083 y el 8084 con la ruta /mqtt.

Artículos relacionados

¿Quién inventó MQTT? La historia, de los oleoductos al IoT

MQTT lo inventaron en 1999 Andy Stanford-Clark, de IBM, y Arlen Nipper, de Arcom, para monitorizar oleoductos vía satélite. Sigue su camino hacia el open source, OASIS, ISO y los brokers MQTT gestionados en la nube de hoy.

8 min de lectura

Por qué tu cliente MQTT se desconecta constantemente (y cómo solucionarlo)

Los bucles de reconexión son uno de los problemas más habituales de MQTT. Conoce las cinco causas típicas, desde los client ID duplicados hasta los timeouts de keep alive y los paquetes demasiado grandes, y sigue un flujo de diagnóstico que localiza la tuya.

9 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.