Understanding the MQTT puzzle -- clients, servers, and connections
The MQTT broker is known as MQTT server in MQTT 3.1.1, and therefore, we will refer to it as the server. However, we must take into account that the documentation for MQTT servers, tools and client libraries can use the old MQTT broker name to refer to the server.
The MQTT server uses the previously explained topic-based filtering to filter and distribute messages to the appropriate subscribers. There are many MQTT server implementations that provide additional message filtering features by providing custom plug-ins. However, we will focus on the features that are part of the MQTT requirements.
As previously explained, in MQTT the publishers and the subscribers are completely decoupled. Publishers and subscribers are MQTT clients that only establish a connection with the MQTT server. An MQTT client can be both a publisher and a subscriber at the same time, that is, the client can publish messages to specific topics and also receive messages that belong to the topics to which the client has subscribed to.
There are MQTT client libraries available for the most popular programming languages and platforms. One of the most important things that we must consider when we select the MQTT client library is the list of MQTT features that they support and the ones that we need for our solution. Sometimes, we can choose between many libraries for a specific programming language and platform and some of them might not implement all the features. We will use many libraries for diverse programming languages and platforms throughout the book and we will learn how to evaluate whether a library is suitable or not for our needs. Specifically, we will work with Python, Java, JavaScript and Swift.
Any device that has a TCP/IP stack and is capable of using an MQTT library can become an MQTT client, that is, a publisher, a subscriber or both a publisher and a subscriber. The MQTT library makes it possible for the device to talk MQTT on top of TCP/IP and to interact with specific types of MQTT servers. For example, any of the following can become an MQTT client: an Arduino board, a Raspberry Pi 3 board, an Intel Joule board, an iPhone, an iPad, a laptop running Windows, a server running Linux, a Macbook running macOS, and Android tablet, among other devices.
There are many MQTT servers available for the most popular platforms, including Linux, Windows and macOS. Many of them are servers that can work as MQTT servers among other features. An MQTT server might implement only a subset of the MQTT capabilities and might have specific limitations. Hence, it is very important to check all the capabilities we will require in our solution before selecting an MQTT server. As happens with other middleware, we have open source versions, free versions and paid versions. Thus, we also have to make sure we select the appropriate MQTT server based on our budget and our specific needs.
Throughout this book, we will work with the Eclipse Mosquitto MQTT server (http://www.mosquitto.org). Mosquitto is an open source MQTT server with an EPL/EDL license that is compatible with MQTT versions 3.1 and 3.1.1. We can take advantage of everything we learn with any other MQTT server such as Erlang MQTT Broker (EMQ), also known as EMQTT (http://www.emqtt.io), and HiveMQ (http://hivemq.com), among others. In addition, we might use our knowledge to work with a cloud-based MQTT server such as CloudMQTT (http://www.cloudmqtt.com).
The MQTT server is the central hub of the publish/subscribe model we previously analyzed. The MQTT server is responsible of the authentication and authorization of the MQTT clients that will be able to become publishers and/or subscribers after they are authenticated and authorized. So, the first thing that an MQTT client must do is to establish a connection with the MQTT server.
In order to establish a connection, the MQTT client must send a CONNECT control packet to the MQTT server with a payload that must include all the necessary information to initiate the connection and proceed with the authentication and authorization. The MQTT server will check the CONNECT packet, perform authentication and authorization and send a response to the client with a CONNACK control packet that we will analyze in detail after understanding the CONNECT control packet. In case the MQTT client sends an invalid CONNECT control packet, the server will automatically close the connection.
The following diagram shows the interaction between an MQTT client and an MQTT server to establish a connection.
Tip
After a successful connection has been established between an MQTT client and an MQTT server, the server will keep the connection open until the client loses the connection or sends a DISCONNECT control packet to the server to close the connection.
The CONNECT control packet must include values for the following fields in the payload and bits for a special flags byte that is included in the control packet. We want to understand the meaning of these fields and flags because we will be able to specify their values when we work with MQTT tools and MQTT client libraries.
ClientId
: The client identifier, also known as Client ID, is a string that identifies each MQTT client that connects to an MQTT server. Each client that connects to the MQTT server must have a uniqueClientId
and the server uses it to identify the state that it holds related to the MQTT session between the client and the server. If a client specifies an empty value as theClientId
, the MQTT server must generate a uniqueClientId
to identify the client. However, this behavior depends on the value specified for theCleanSession
field.CleanSession
: The clean session flag is a boolean value that specifies what happens after an MQTT client disconnects from the MQTT server and then reconnects. IfCleanSession
is set to1
ortrue
, the client indicates to the MQTT server that the session will only last as long as the network connection is alive. After the MQTT client disconnects from the MQTT server, any information related to the session is discarded. A new connection from the same MQTT client to the MQTT server will not use the data from the previous session and will be a new clean session. IfCleanSession
is set to0
orfalse
, we will work with a persistent session. In this case, the MQTT server stores all the subscriptions for the MQTT client and when the MQTT client disconnects, the MQTT server stores all the messages that arrive with specific quality of service levels that match the subscriptions that the MQTT client had at the time the disconnection occurred. This way, when the same MQTT client establishes a new connection with the MQTT server, the MQTT client will have the same subscriptions and will receive all the messages that it couldn't receive when it lost the connection. We will dive deep on the quality of service level for the messages and their relationship with the clean session flag or the persistent session option later.
Tip
When the clean session flag is set to 0
or false
, the client indicates to the server that is wants a persistent session. We just have to remember a clean session is the opposite of a persistent session.
UserName
: If the client wants to specify a user name to request authentication and authorization from the MQTT server, it must set theUserName
flag to1
ortrue
and specify a value for theUserName
field.password
: If the client wants to specify a password to request authentication and authorization from the MQTT server, it must set thePassword
flag to1
ortrue
and specify a value for thePassword
field.
Tip
We will dedicate the entire next chapter to MQTT security, and therefore, we just mention the fields and the flags that are included in the CONNECT
control packtet.
ProtocolLevel
: The protocol level value indicates the MQTT protocol version that the MQTT client requests the MQTT server to use. Remember we will always work with MQTT version 3.1.1.KeepAlive
:KeepAlive
is a time interval expressed in seconds. If the value for keep alive is not equal to0
, the MQTT client commits to send control packets to the server within the time specified forKeepAlive
. If the MQTT client doesn't have to send any control packet, it must send aPINGREQ
control packet to the MQTT server, that is, a ping request to tell the MQTT server that the client connection is alive. The MQTT server responds to thePINGREQ
control packet with aPINGRESP
response to the MQTT client, that is, a ping response to tell the MQTT client that the connection with the MQTT server is alive. The connection is closed when there is an absence of any of these control packets. If the value for keep alive is0
, the keep alive mechanism is turned off.Will
,WillQoS
,WillRetain
,WillTopic
andWillMessage
: These flags and fields allow the MQTT client to take advantage of the last will and testament feature of MQTT. If the MQTT client sets theWill
flag to1
or true, it specifies that it wants the MQTT server to store a last will message associated with the session. TheWillQoS
flag specifies the desired quality of service for the lastWillMessage
and theWillRetain
flag indicates whether this messsage must be retained when it is published or not. If the MQTT client sets theWill
flag to1
or true, it must specify the topic for theWillMessage
and the message in theWillTopic
andWillMessage
fields. If the MQTT client is disconnected or loses the connection with the MQTT server, the MQTT server will publish the message specified in theWillMessage
field to the topic indicated in theWillTopic
field with the chosen quality of service. We will analyze this feature in detail later.
The MQTT server will process a valid CONNECT
control packet and it will respond with a CONNACK
control packet. This control packet will include values for the following flags included in the header. We want to understand the meaning of these flags because we will be able to retreive their values when we work with MQTT tools and MQTT client libraries.
SessionPresent
: If the MQTT server received a connection request with theCleanSession
flag set to1
ortrue
, the value for theSessionPresent
flag will be0
orfalse
because no stored session will be reused. If theCleanSession
flag was set to0
orfalse
in the connection request, the MQTT server will work with a persistent session and the value for theSessionPresent
flag will be1
ortrue
if the server had a persistent session for the client from a previous connection and retrieves it. Otherwise, SessionPresent will be0
orfalse
. The MQTT client that wanted to work with a persistent session can use the value of this flag to determine whether it has to request subscription to the desired topics or whether the subscriptions have been restored from the persisted session.ReturnCode
: If the authorization and authentication passed and the connection was successfully established, the value forReturnCode
will be0
. Otherwise, the return code will be different than0
and the network connection between the client and the server will be closed. The following table shows the possible values forReturnCode
with their meaning.
ReturnCode value |
Description |
|
The connection was accepted |
|
The connection was refused because the MQTT server doesn't support the MQTT protocol version requested by the MQTT client in the CONNECT control packet |
|
The connection was refused because the |
|
The connection was refused because the network connection was established but the MQTT service isn't available |
|
The connection was refused because the user name or password values are malformed |
|
The connection was refused because authorization failed |