En un artículo anterior, analizamos
el protocolo Modbus , que es el estándar de facto de la industria para la interacción
M2M . Desarrollado en 1979, tiene una serie de inconvenientes importantes que MQTT resuelve.
El protocolo MQTT es bastante joven (estandarizado solo en 2016), pero ya ha logrado ser ampliamente utilizado en la industria e IoT. Fue especialmente diseñado para ser lo más compacto posible, para canales de Internet inestables y dispositivos de baja potencia, y le permite garantizar la entrega de mensajes en caso de pérdida y desconexión de paquetes.
Características clave del protocolo MQTT:
- Compacto y liviano : sobrecarga mínima de transferencia de datos para ahorrar tráfico.
- Resistencia a las pérdidas : entrega garantizada en condiciones de conexiones de red inestables.
- Asíncrono : le permite atender una gran cantidad de dispositivos y no depende de los retrasos de la red.
- Soporte de QoS : la capacidad de controlar la prioridad del mensaje y garantizar la entrega del mensaje al destinatario.
- Configuración dinámica : no requiere coordinación previa de campos y formatos de datos, se puede configurar sobre la marcha.
- Funciona para NAT : los clientes pueden estar detrás de NAT, solo el servidor (intermediario) debe tener una IP real. Le permite prescindir de VPN y reenvío de puertos.
- Direccionamiento conveniente : los campos de datos tienen nombres de texto que los humanos pueden entender. No es necesario recordar direcciones digitales y compensaciones de bits.
En el artículo, compararemos MQTT y Modbus, analizaremos la estructura del protocolo, los conceptos básicos e intentaremos usar el broker MQTT en la nube como ejemplo en una conexión a Internet inestable.
Historial de protocolo MQTT
MQTT fue desarrollado por IBM en 1999, y inicialmente se usó internamente para sus soluciones.
En noviembre de 2011, IBM y Eurotech anunciaron su participación en el grupo de trabajo Eclipse M2M y la transferencia del código MQTT al proyecto Eclipse Paho.
En 2013, el consorcio
OASIS (Organización para el Avance de los Estándares de Información Estructurada) comenzó el proceso de estandarización del protocolo MQTT. Hasta este momento, la especificación del protocolo se ha publicado bajo una licencia gratuita, y compañías como Eurotech (anteriormente conocida como Arcom) ya utilizan el protocolo en sus productos.
En octubre de 2014, OASIS publicó el primer estándar oficial de protocolo MQTT.
En 2016, el protocolo fue estandarizado por la Organización Internacional de Normalización ISO y recibió el número ISO / IEC 20922.
Desde 2014, el interés en el protocolo comienza a crecer rápidamente y, a juzgar por el calendario de Google Trends, hoy supera el interés en Modbus.
Benchmark de tendencias de GoogleConceptos basicos
MQTT tiene una arquitectura cliente-servidor. La mensajería se realiza a través de un servidor central llamado intermediario. En condiciones normales, los clientes no pueden comunicarse directamente entre sí, y todo el intercambio de datos se realiza a través de un intermediario.
Los clientes pueden actuar como proveedores de datos (Editor) y como destinatarios de datos (Suscriptor). En una traducción al ruso, estos términos a menudo se traducen como editor y suscriptor, pero para evitar confusiones, usaremos solo la terminología original.
En el protocolo MQTT, los clientes se comunican entre sí a través de un nodo centralA nivel de aplicación, el protocolo se ejecuta sobre TCP / IP y puede conectar fácilmente objetos remotos directamente a través de Internet, sin la necesidad de túneles VPN. Es suficiente para el corredor tener una dirección IP real y todos los clientes pueden conectarse a ella. En este caso, los clientes pueden estar ubicados detrás de NAT. Dado que los clientes inician la conexión en el protocolo MQTT, no se requiere el reenvío de puertos para establecer una conexión, mientras que en Modbus / TCP el servidor inicia una conexión (maestra), que requiere accesibilidad directa a la red.
El puerto de agente MQTT estándar para las conexiones TCP entrantes es
1883 . Cuando se usa una conexión SSL segura,
se usa el puerto
8883 .
Corredor
Un corredor es el centro central de MQTT para la interacción con el cliente. El intercambio de datos entre clientes ocurre solo a través de un corredor. El corredor puede ser un software de servidor o un controlador. Sus tareas incluyen recibir datos de clientes, procesar y almacenar datos, entregar datos a clientes y monitorear la entrega de mensajes.
Editor / suscriptor
Para comprender la diferencia entre el editor y el suscriptor, tomemos un ejemplo simple: un sensor de humedad mide la humedad en una habitación y, si cae por debajo de cierto nivel, el humidificador se enciende.
En este caso, el sensor de humedad actúa como un
editor : su tarea es solo publicar datos en el agente. El humidificador actúa como un
Suscriptor : se suscribe a las actualizaciones de los datos de humedad y recibe datos actualizados del agente, mientras que el humidificador puede decidir en qué punto encender la humidificación.
En este esquema, los clientes MQTT, es decir, el sensor y el humidificador, no son conscientes de la existencia de los demás y no interactúan directamente. El agente puede recibir datos de varias fuentes, manipularlos, por ejemplo, calcular el valor promedio de varios sensores y devolver los datos procesados al suscriptor.
El editor envía datos al agente, el suscriptor se suscribe a las actualizaciones de estos datosAl mismo tiempo, el asincronismo del protocolo MQTT establece que el sensor y el humidificador pueden estar en línea en diferentes momentos, perder paquetes y ser inaccesibles. El corredor se encargará de almacenar los últimos datos recibidos del sensor en la memoria y garantizará su entrega al humidificador.
Tema
MQTT utiliza temas para identificar entidades, en la traducción al ruso también se denominan canales. Los temas consisten en caracteres UTF8 y tienen una estructura de árbol similar a un sistema de archivos UNIX. Este es un mecanismo conveniente para nombrar entidades en una forma legible para humanos.
Un ejemplo de temas en MQTT
Este enfoque le permite ver visualmente qué datos se transmiten, y es conveniente desarrollar y depurar el código sin tener que memorizar la dirección digital de la ubicación de los datos, como se hace en Modbus.
Los temas también incluyen la sintaxis comodín, familiar para aquellos que han trabajado con el sistema de archivos UNIX. El comodín puede ser de un solo nivel y de varios niveles.
Un comodín de un solo nivel se indica con un
+ .
Por ejemplo, para recibir datos de sensores de temperatura en todas las habitaciones de la casa, el suscriptor debe suscribirse a dicho tema:
home/+/temperature
Como resultado, se suscribirá para recibir datos de dichos sensores:
home/kitchen/temperature home/sleeping-room/temperature home/living-room/temperature home/outdoor/temperature
Un comodín multinivel se indica con el símbolo "
# ".
Un ejemplo de obtención de datos de todos los sensores en todas las habitaciones de la casa:
home/#
Suscribirse a dicho tema le permitirá recibir datos de dichos sensores:
home/kitchen/temperature home/kitchen/humidity home/kitchen/light home/sleeping-room/temperature home/sleeping-room/humidity home/sleeping-room/light ....
Identificación del cliente
Para el control de acceso, MQTT proporciona autenticación de cliente, a diferencia del protocolo Modbus, que no tiene dicha función. Los siguientes campos se utilizan para el control de acceso:
ClientId : (campo obligatorio) identificador único del cliente. Debe ser único para cada cliente. La versión actual del estándar MQTT 3.1.1 le permite usar el campo ClientId vacío si no necesita guardar el estado de la conexión.
Nombre de usuario : inicio de sesión (campo opcional) para autenticación, en formato UTF-8. Puede que no sea único. Por ejemplo, un grupo de clientes puede iniciar sesión con el mismo nombre de usuario / contraseña.
Contraseña : (campo opcional) solo se puede enviar junto con el campo Nombre de usuario, mientras que el Nombre de usuario se puede transmitir sin el campo Contraseña. Máximo 65535 bytes. Es importante saber que el nombre y la contraseña se transmiten de forma clara, por lo tanto, si los datos se transmiten a través de redes públicas, debe usar SSL para cifrar la conexión.
Estructura del paquete
Como se mencionó anteriormente, en el protocolo MQTT, los clientes siempre inician una conexión, independientemente de si son destinatarios (Suscriptor) o proveedores (Editor) de datos. Analizaremos el paquete con la conexión que fue interceptada usando el programa Wireshark.
Paquete MQTT transmitido por un canal no encriptadoEl encabezado TCP muestra que el paquete se transmitió en el puerto 1883, es decir, no se utiliza el cifrado, lo que significa que todos los datos están disponibles en forma clara, incluidos el inicio de sesión y la contraseña.
Titular
El tipo de mensaje es Conectar (comando 0x0001), estableciendo una conexión con el intermediario. Equipos principales: conectar, desconectar, publicar, suscribir, cancelar suscripción. También hay comandos de reconocimiento, mantener vivo, etc.
DUP de marca : significa que el mensaje se retransmite, se usa solo en los tipos de mensaje PUBLISH, SUBSCRIBE, UNSUBSCRIBE, PUBREL, para los casos en que el corredor no recibió la confirmación de la recepción del mensaje anterior.
Nivel de calidad del servicio: indicador de calidad de servicio. Discutiremos este tema con más detalle más adelante.
Retener : los datos publicados con el indicador de retención se almacenan en el intermediario. Tras la subsiguiente suscripción a este tema, el agente enviará inmediatamente un mensaje con esta bandera. Se usa solo en mensajes de tipo Publicar.
Uso práctico

Ahora, habiéndonos familiarizado con la teoría, intentemos trabajar con MQTT en la práctica. Para esto, utilizaremos el programa abierto
Mosquitto , que puede funcionar tanto en modo cliente como en modo servidor (intermediario). Funciona en Windows, macOS, Linux. El programa es muy conveniente para depurar y estudiar el protocolo MQTT, mientras que también es ampliamente utilizado en operaciones industriales. Lo utilizaremos como cliente para enviar y recibir datos de un agente de nube remoto.
Muchos proveedores de la nube brindan servicios de agente MQTT, como
Microsoft Azure IoT Hub ,
Amazon AWS IoT y otros. En este ejemplo, utilizaremos el servicio Cloudmqtt.com, ya que tiene el registro más simple y una tarifa gratuita es suficiente para la capacitación.
Después del registro, los detalles para conectarse a un corredor están disponibles en su cuenta. Como nos conectamos al servidor a través de redes públicas de Internet, es razonable usar un puerto SSL para encriptar el tráfico.
Detalles de acceso del agente MQTT en la cuenta personal del proveedor de la nubeLa flexibilidad del protocolo MQTT permite al cliente transferir datos no definidos previamente en el intermediario. Es decir, no es necesario crear previamente los temas necesarios en los que Publisher puede escribir datos. Usando los datos recibidos de su cuenta personal, intentaremos redactar manualmente una solicitud para publicar datos en el tema
habr / test / random y leerlos.
mosquitto_sub - utilidad de cliente de suscriptor
mosquitto_pub - utilidad del cliente editor
Primero, conéctese al corredor como suscriptor y suscríbase para recibir datos del tema
habr / prueba / aleatorio .
mosquitto_sub -d --capath /etc/ssl/certs/ --url mqtts://hwjspxxt:7oYugN7Fa5Aa@postman.cloudmqtt.com:27529/habr/test/random Client mosq/zEPZz0glUiR4aEipZA sending CONNECT Client mosq/zEPZz0glUiR4aEipZA received CONNACK (0) Client mosq/zEPZz0glUiR4aEipZA sending SUBSCRIBE (Mid: 1, Topic: habr/test/random, QoS: 0, Options: 0x00) Client mosq/zEPZz0glUiR4aEipZA received SUBACK
Se puede ver que la conexión fue exitosa, y nos suscribimos al tema
habr / test / random , y ahora estamos esperando datos del broker sobre este tema.
Como se utiliza una conexión SSL, para verificar el certificado, debe especificar la ruta por la cual el programa buscará los certificados de cifrado raíz. Dado que el servicio en nuestro ejemplo usa un certificado emitido por una autoridad de certificación confiable, indicamos la ruta al almacén del sistema para los certificados raíz: --capath / etc / ssl / certs /
En el caso de un certificado autofirmado, debe especificar la ruta a la CA deseada. También es importante considerar la diferencia en el formato URI para las conexiones SSL - mqtt s : //, y las conexiones no encriptadas - mqtt: //. En el caso de un error de verificación del certificado, el programa finaliza sin un mensaje de error. Para una salida más detallada, puede usar el modificador --debug
Ahora intentemos publicar los datos en el tema sin interrumpir el primer programa.
mosquitto_pub -d --capath /etc/ssl/certs/ --url mqtt://hwjspxxt:7oYugN7Fa5Aa@postman.cloudmqtt.com:27529/habr/test/random -m " !" Client mosq/sWjh9gf8DRASrRZjk6 sending CONNECT Client mosq/sWjh9gf8DRASrRZjk6 received CONNACK (0) Client mosq/sWjh9gf8DRASrRZjk6 sending PUBLISH (d0, q0, r0, m1, 'habr/test/random', ... (22 bytes)) Client mosq/sWjh9gf8DRASrRZjk6 sending DISCONNECT
Se puede ver que los datos fueron recibidos con éxito por el servidor y publicados en el tema deseado. Al mismo tiempo, en la primera ventana en la que se ejecuta el programa mosquitto_sub, vemos cómo se recibió el mensaje, mientras que incluso Unicode funciona, puede ver el mensaje en ruso.
Client mosq/zEPZz0glUiR4aEipZA received PUBLISH (d0, q0, r0, m0, 'habr/test/random', ... (22 bytes)) !
QoS y garantía de entrega
Sin embargo, enviar un mensaje en tiempo real no sorprenderá a nadie, porque lo mismo se puede hacer incluso con la utilidad banal
nc . Por lo tanto, intentaremos simular una conexión inestable entre el suscriptor y el remitente. Imagine que ambos clientes trabajan a través de GPRS, con una gran pérdida de paquetes, e incluso una conexión TCP exitosa es rara, y debe asegurarse de que el suscriptor tenga la garantía de recibir un mensaje del remitente. En este caso, las opciones de QoS vienen al rescate.
De manera predeterminada, el indicador de
QoS se establece
en 0 para los mensajes, lo que significa "Activar y olvidar": el editor publica el mensaje en el intermediario, pero no requiere que se garantice que el mensaje se entregue al suscriptor. Esto es adecuado para datos cuya pérdida no es crítica, por ejemplo, para mediciones regulares de humedad o temperatura.
QoS 1: al menos una vez, al menos uno . Este indicador significa que hasta que el editor reciba la confirmación de entrega al suscriptor, esta publicación se enviará al intermediario y luego al suscriptor. Por lo tanto, el suscriptor debe recibir este mensaje al menos una vez.
QoS 2: Exactamente una vez, uno garantizado . El indicador QoS, que proporciona la máxima garantía de entrega de mensajes mediante el uso de procedimientos adicionales para la confirmación y finalización de la publicación (PUBREC, PUBREL, PUBCOMP). Aplicable a situaciones en las que es necesario excluir cualquier pérdida y duplicación de datos de los sensores. Por ejemplo, cuando se activa una alarma desde un mensaje recibido, se realiza una llamada de emergencia.
Para simular una comunicación deficiente, desactive ambos clientes e intente enviar un mensaje con la mayor prioridad de QoS, y también agregue la opción Retener para que el mensaje enviado se guarde en el intermediario.
mosquitto_pub --retain --qos 2 -d --capath /etc/ssl/certs/ --url mqtt://hwjspxxt:7oYugN7Fa5Aa@postman.cloudmqtt.com:27529/habr/test/random -m " !" Client mosq/Xwhua3GAyyY9mMd05V sending CONNECT Client mosq/Xwhua3GAyyY9mMd05V received CONNACK (0) Client mosq/Xwhua3GAyyY9mMd05V sending PUBLISH (d0, q2, r1, m1, 'habr/test/random', ... (37 bytes)) Client mosq/Xwhua3GAyyY9mMd05V received PUBREC (Mid: 1) Client mosq/Xwhua3GAyyY9mMd05V sending PUBREL (m1) Client mosq/Xwhua3GAyyY9mMd05V received PUBCOMP (Mid: 1, RC:0) Client mosq/Xwhua3GAyyY9mMd05V sending DISCONNECT
Ahora, después de un tiempo, nuestro destinatario finalmente pudo establecer una conexión a Internet y conectarse al corredor:
mosquitto_sub -d --capath /etc/ssl/certs/ -d --url mqtts://hwjspxxt:7oYugN7Fa5Aa@postman.cloudmqtt.com:27529/habr/test/random Client mosq/VAzcLVMB1MiWhYxoJS sending CONNECT Client mosq/VAzcLVMB1MiWhYxoJS received CONNACK (0) Client mosq/VAzcLVMB1MiWhYxoJS sending SUBSCRIBE (Mid: 1, Topic: habr/test/random, QoS: 0, Options: 0x00) Client mosq/VAzcLVMB1MiWhYxoJS received SUBACK Subscribed (mid: 1): 0 Client mosq/r6UwPnDvx8aNInpPF6 received PUBLISH (d0, q0, r1, m0, 'habr/test/random', ... (37 bytes)) !
Conclusión
MQTT es un protocolo moderno y avanzado, desprovisto de muchos de los inconvenientes de sus predecesores. Su flexibilidad le permite agregar dispositivos cliente sin configurar un corredor, lo que ahorra mucho tiempo. El umbral de entrada para comprender y configurar el protocolo es bastante bajo, y la presencia de bibliotecas para muchos lenguajes de programación le permite elegir cualquier pila de tecnología para el desarrollo. La garantía de entrega de mensajes distingue significativamente a MQTT de sus predecesores y le permite no perder tiempo desarrollando innecesariamente sus propios mecanismos de control de integridad a nivel de red.