There protocol uses the two exchanges of packets in order to provide the exactly-once semantics of QoS 2 messaging.
C --- PUBLISH --> S
*1
C <-- PUBREC --- S
*2
C --- PUBREL --> S
*3
C <-- PUBCOMP --- S
*4
When the server receives the PUBLISH
it stores the ID and forwards the message on. When the server receives the PUBREL
it can then delete the ID.
If the connection breaks at *1
, the client does not know if the server received the message or not. It resends the PUBLISH
(containing the full message payload). If the server had already received the message it just needs to respond with the PUBREC
.
If the connection breaks at *2
, the client may or may not have received the PUBREC
. If it didn't, it will resend the PUBLISH
. Otherwise it will send the PUBREL
.
If the connection breaks at *3
, the client does not know if the server received the message or not. It resends the PUBREL
- which does not contain full message payload.
If the connection breaks at *4
and the client hasn't received the PUBCOMP
it can resend the PUBREL
.
There are two observations for why the two exchanges are needed:
- the server is not required to remember every message it has ever seen. There is a very well defined period for it to store the message ID. The two exchanges allow both sides to have certainty that the message has been delivered exactly once.
- the client does not need to resend the PUBLISH multiple times (unless the connection is interrupted at
*1
. Given the protocol is intended to minimise network traffic, this is an important feature.