Retransmission mechanism of MQTT
There are 3 levels QoS in MQTT, the retransmission mechanism only work under QoS 1 or QoS 2.
I will use sender and receiver instead of publisher, subscriber and broker in the following.
When publish events occur, the sender is the publisher and the receiver is the broker.
When subscribe events occur, the sender is the broker, and the receiver is the subscriber.
0, there is no retransmission. Sender will drop the message once it sent the message package, no matter whether the peer receive it.
1, MQTT use
Sender should maintain a queue, for example a
vector<Message*> in the memory and the data in queue may be also persisted on the disk for restart use. Since sender send the message at the front of the queue, it should wait the receive send
PUBACK back, before sender receive the
PUBACK package, it should keep the message not be lost.
It works like this:
sender — PUBLISH message of mid001 -> receiver
sender <- PUBACK message id of mid001 — receiver
sender remove mid001
If sender hadn’t receive the
PUBACK package and the connection was closed or terminated, sender would keep the mid001 message in the queue, once the receiver connect again, sender will send the message mid001 again.
Obviously, if the connection was broken before the receiver got the message mid001, receiver will got the message mid001 in the next connection, and it will only got the message mid001 once. BUT if the connection was broken after the receiver got the
PUBLISH package, and before the sender receive the
PUBACK package, when the connection was established again, sender will send mid001 again, in the case, receiver will got the message mid001 twice(and the
PUBACK package may lose again in the second connection, then receiver will got the message thrice in the 3rd connection).
That’s why QoS 1 will ensure the receiver get one message at least once.
To make one message transmit extract once, MQTT has QoS 2.
QoS 2 is more complex and costly. It use
PUBCOMP 4 command. The data formats are:
It works like this:
sender(mid001 in queue) — PUBLISH -> receiver
sender(mid001 in queue) <- PUBREC — receiver(mid001 in buffer)
sender(mid001 in-fly) -> PUBREL — receiver(mid001 in buffer)
sender(mid001 in-fly) <- PUBCOMP -receiver(mid001 was used)
sender remove mid001
The retransmission mechanism is:
- Receiver won’t really active the mid001 message after the first time it was received. It just send a PUBREC package with the message id to the sender to tell the peer message mid001 was copied. Receiver will only consume the message after it got the PUBREL package.
- The transmission divide into two steps, the first step the message was copied in the receiver’s buffer, but not really be used, the second step the id(a 16-bit number) of message was transmit, and make the message really active.
- In the 4-times communication, if the connection was broken in one command, the peers will try it again in the next time they connect.
- If the connection was broken in the PUBLISH command, sender will send the message again.
- if the connection was broken in the PUBREC command, because sender didn’t know whether the PUBLISH command was received, it will send a new message with the same id, the receiver will find there is a duplicate message in buffer then drop either one and send a PUBREC command again. Once sender got the PUBREC command, it will mark the message mid001 as in-fly message and send a PUBREL command.
- if the connection was broken in the PUBREL command, sender will send a new PUBREL command in the next connection. Because sender knew the receiver has the message body, it just need to active it.
- If the connection was broken in the PUBCOMP command, sender will send a new PUBREL command in the next connection, because sender will find there is a in-fly message. Receiver got the PUBREL command but find there is no such a message in its buffer, receiver will do nothing but send a PUBCOMP command to complete the communication for message mid001.
- In the 2 steps transmission, a message will be active only the 4-time communication complete. This mechanism makes the message will be active exactly once.