Comment fonctionne MQTT ? En bref, les clients ouvrent une connexion de longue durée vers un broker, déclarent les topics qui les intéressent, et le broker transmet chaque message publié aux abonnés correspondants. Dans cet article, vous allez suivre ce processus paquet par paquet, de la connexion TCP à CONNECT, SUBSCRIBE, PUBLISH, au keep alive et à la déconnexion, et reproduire vous-même toute la trace sur le serveur MQTT public gratuit.
Les trois rôles : publisher, subscriber et broker
MQTT ne compte que deux types de participants : les clients et les brokers. Un client peut publier, s'abonner, ou les deux. Le broker se trouve au milieu, reçoit chaque message et décide qui le reçoit.
- Les publishers envoient des messages sur un topic, une chaîne comme
plant1/line2/temperature. Ils ne savent pas qui les reçoit et ne s'en soucient pas. - Les subscribers indiquent au broker quels topics, ou quels motifs de topics, ils veulent recevoir. Ils ne savent pas qui envoie.
- Le broker authentifie les clients, suit les abonnements et les sessions, et achemine chaque message vers tous les abonnés correspondants.
Ce découplage est au cœur de la conception. Un capteur n'a pas besoin de l'adresse IP d'un tableau de bord, les deux n'ont pas besoin d'être en ligne au même moment si les sessions sont persistantes, et ajouter un cinquième consommateur ne demande aucune modification du capteur. Pour en savoir plus sur le rôle du broker, voir ce que fait un broker MQTT, et pour le modèle lui-même, le modèle publication/abonnement de MQTT.
Étape 1 : ouvrir une connexion réseau
MQTT fonctionne sur un flux d'octets fiable et ordonné, normalement TCP. Le client ouvre une connexion TCP vers le broker, sur le port 1883 pour MQTT en clair ou 8883 pour MQTT sur TLS. Les navigateurs, qui ne peuvent pas ouvrir de sockets TCP bruts, transportent MQTT dans un WebSocket (sur ConnectMQ, 8083 ou 8084 avec le chemin /mqtt). Rien de spécifique à MQTT ne s'est encore produit ; ce n'est que le tuyau.
Avec TLS, une négociation a alors lieu : le client vérifie le certificat du broker et les deux parties s'accordent sur les clés de chiffrement. Tous les paquets MQTT suivants sont chiffrés.
Étape 2 : CONNECT et CONNACK
Le premier paquet du client doit être CONNECT. Il contient :
| Champ | Rôle |
|---|---|
| Nom et niveau du protocole | MQTT et 4 (3.1.1) ou 5 (5.0) |
| Client ID | Identifie la session ; doit être unique par connexion |
| Clean session / clean start | Repartir de zéro ou reprendre une session enregistrée |
| Keep alive | Nombre maximal de secondes entre deux paquets du client |
| Nom d'utilisateur et mot de passe | Identifiants facultatifs |
| Last Will | Message facultatif que le broker publie si le client disparaît |
| Propriétés (MQTT 5) | Expiration de session, receive maximum, taille maximale des paquets, etc. |
Le broker valide tout cela et répond par CONNACK. En MQTT 5, ce paquet contient un reason code : 0x00 en cas de succès, ou une erreur comme des identifiants incorrects, une absence d'autorisation ou, sur un broker soumis à des quotas, 0x97 quota exceeded. Il indique aussi si une session précédente a été reprise (drapeau session present) et peut informer le client des limites du serveur. Tant qu'un CONNACK de succès n'est pas arrivé, le client ne doit rien envoyer d'autre.
Étape 3 : SUBSCRIBE et SUBACK
Un client qui veut recevoir des messages envoie SUBSCRIBE avec un ou plusieurs filtres de topic et une QoS demandée pour chacun. Les filtres peuvent contenir des wildcards : + correspond à exactement un niveau et # à tout ce qui se trouve sous un niveau. Par exemple, plant1/+/temperature correspond à plant1/line2/temperature mais pas à plant1/line2/motor/temperature.
Le broker répond par SUBACK, en indiquant la QoS accordée (ou un code d'échec) pour chaque filtre. La QoS accordée peut être inférieure à celle demandée si le broker la plafonne. S'il existe des retained messages sur des topics correspondants, le broker les envoie immédiatement : c'est ainsi qu'un nouveau tableau de bord connaît instantanément l'état courant.
Étape 4 : PUBLISH et les échanges de QoS
Pour envoyer des données, un client envoie PUBLISH avec un nom de topic, un payload (n'importe quels octets, souvent du JSON), un niveau de QoS et un drapeau retain. La suite dépend de la QoS :
- QoS 0, au plus une fois. PUBLISH, et c'est tout. Aucun acquittement ; si la connexion tombe au mauvais moment, le message est perdu.
- QoS 1, au moins une fois. Le destinataire répond par PUBACK. Si l'émetteur ne le reçoit pas, il renvoie le message avec le drapeau duplicate positionné : le destinataire peut donc voir le message deux fois.
- QoS 2, exactement une fois. Un échange en quatre temps : PUBLISH, PUBREC, PUBREL, PUBCOMP. Plus lent, mais sans doublons.
Ces échanges ont lieu saut par saut : une fois entre le publisher et le broker, et séparément entre le broker et chaque subscriber. Le broker transmet ensuite le message à chaque client dont le filtre correspond, en utilisant la plus basse des deux QoS, celle de la publication ou celle accordée à l'abonnement. Tous les compromis sont détaillés dans les niveaux de QoS MQTT expliqués.
Si le drapeau retain est positionné, le broker stocke aussi le message comme dernière valeur connue pour ce topic et le remet aux futurs abonnés.
Étape 5 : le keep alive avec PINGREQ et PINGRESP
Même inactif, un client doit prouver qu'il est vivant dans l'intervalle de keep alive. S'il n'a rien à publier, il envoie PINGREQ et le broker répond PINGRESP. Si le broker n'entend rien pendant environ une fois et demie la période de keep alive, il considère le client comme mort, ferme la connexion et publie le Last Will du client, s'il en a défini un. C'est ainsi que les tableaux de bord apprennent qu'un appareil est passé hors ligne sans que personne n'ait à interroger.
Étape 6 : DISCONNECT et sessions
Un arrêt propre envoie DISCONNECT, qui indique au broker de ne pas publier le Last Will. Ce qui survit dépend des paramètres de session : avec clean start et sans expiration de session, le broker oublie les abonnements du client. Avec une session persistante (expiration de session MQTT 5 supérieure à zéro), le broker conserve les abonnements et met en file les messages QoS 1 et 2 jusqu'au retour du client ou jusqu'à l'expiration.
Reproduisez la trace vous-même
Vous pouvez observer tout le cycle de vie sur le serveur MQTT public gratuit, broker.connectmq.com. Les clients Mosquitto affichent chaque paquet avec -d. Choisissez d'abord un identifiant aléatoire unique ; ici, c'est q7m3x9.
# Terminal 1 : abonné avec sortie de débogage
mosquitto_sub -h broker.connectmq.com -p 1883 -i sub-q7m3x9 -V mqttv5 -d \
-t 'connectmq/demo/q7m3x9/#' -q 1
# Terminal 2 : publisher avec sortie de débogage
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 sortie de l'abonné ressemble à ceci (les détails varient selon la version) :
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
Et celle du publisher :
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
Lisez les drapeaux de la ligne PUBLISH : d0 (pas un doublon), q1 (QoS 1), r0 (non retained), m1 (identifiant de paquet 1). Essayez -q 2 et vous verrez PUBREC, PUBREL et PUBCOMP ; ajoutez -r au publisher, redémarrez l'abonné, et le retained message arrive immédiatement après SUBACK. L'espace public est lisible par n'importe qui : n'envoyez que des données de test.
Le même flux en Python
Les bibliothèques cachent les paquets derrière des callbacks, mais chacun correspond à une étape ci-dessus.
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 entrant
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()
Les idées reçues courantes
- « Le broker stocke tous les messages. » Seulement les retained messages (un par topic) et les messages en file pour les sessions persistantes. MQTT n'est ni une base de données ni un journal.
- « Les topics doivent être créés au préalable. » Non, les topics existent dès que quelqu'un publie ou s'abonne.
- « La QoS 2 de bout en bout. » La QoS s'applique saut par saut et est abaissée au niveau de l'abonnement.
- « Les client ID peuvent être partagés. » Une seconde connexion avec le même ID éjecte la première.
- « MQTT utilise UDP. » MQTT standard nécessite TCP ou un autre flux fiable ; MQTT-SN est la variante pour UDP et les réseaux similaires.
Pour aller plus loin, le tutoriel MQTT construit un projet complet, les paquets de contrôle MQTT détaille chaque type de paquet, et les spécifications officielles sont publiées sur mqtt.org.
Essayez MQTT sur ConnectMQ
Expérimentez librement sur broker.connectmq.com, puis créez un broker Serverless (Free) sur app.connectmq.com, sans carte bancaire, quand vous voulez des topics privés et authentifiés. ConnectMQ est un broker MQTT cloud qui prend en charge MQTT 3.1.1 et 5.0, avec un client intégré au navigateur et un explorateur de topics en direct pour observer en temps réel les flux décrits ici. Quand vous passez en production, il fonctionne comme un broker MQTT managé.
Questions fréquentes
Comment fonctionne MQTT en termes simples ?
Les appareils se connectent à un broker central, s'abonnent aux topics qui les intéressent et publient des messages sur des topics. Le broker transmet chaque message à tous les abonnés correspondants.
Les publishers et les subscribers se connectent-ils directement entre eux ?
Non. Chaque client se connecte uniquement au broker, c'est pourquoi les appareils n'ont jamais besoin de connaître leurs adresses respectives.
Que se passe-t-il si un abonné est hors ligne au moment où un message est publié ?
Avec une session persistante et une QoS 1 ou 2, le broker met le message en file jusqu'à la reconnexion de l'abonné ou l'expiration de la session. Sinon, le message n'est pas livré à ce client, même si un retained message lui donnera toujours la dernière valeur.
Quel port MQTT utilise-t-il ?
1883 pour TCP en clair et 8883 pour TLS. Les ports WebSocket varient selon le broker ; ConnectMQ utilise 8083 et 8084 avec le chemin /mqtt.



