Editor’s Note: The MQTT lightweight messaging protocol is a fundamental part of the technical foundation of most IoT applications and their underlying services. Taken from the book, MQTT Essentials – A Lightweight IoT Protocol by Gastón C. Hillar, this series of articles walks developers through MQTT fundamentals and shows how to get started with this essential protocol.
In this first installment of the series, the author introduced convenient scenarios for this protocol and continues with a description of the publish-subscribe pattern and message filtering. This article continues the series with a description of the three basic entities involved in MQTT communications.
Adapted from MQTT Essentials – A Lightweight IoT Protocol, by Gastón C. Hillar.
Chapter 1. Lightweight Messaging w1ith MQTT 3.1.1 and Mosquitto (Continued)
By Gastón C. Hillar
For the previous installment in this series, see MQTT essentials – Scenarios and the pub-sub pattern.
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.
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.
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 unique ClientId 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 the ClientId, the MQTT server must generate a unique ClientId to identify the client. However, this behavior depends on the value specified for the CleanSession 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. If CleanSession is set to 1 or true, 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. If CleanSession is set to 0 or false, 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.
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 the UserName flag to 1 or true and specify a value for the UserName field.
- password: If the client wants to specify a password to request authentication and authorization from the MQTT server, it must set the Password flag to 1 or true and specify a value for the Password field.
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 packet.
- 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 to 0, the MQTT client commits to send control packets to the server within the time specified for KeepAlive. If the MQTT client doesn’t have to send any control packet, it must send a PINGREQ 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 the PINGREQ control packet with a PINGRESP 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 is 0, the keep alive mechanism is turned off.
- Will, WillQoS, WillRetain, WillTopic and WillMessage: 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 the Will flag to 1 or true, it specifies that it wants the MQTT server to store a last will message associated with the session. The WillQoS flag specifies the desired quality of service for the last WillMessage and the WillRetain flag indicates whether this messsage must be retained when it is published or not. If the MQTT client sets the Will flag to 1 or true, it must specify the topic for the WillMessage and the message in the WillTopic and WillMessage fields. If the MQTT client is disconnected or loses the connection with the MQTT server, the MQTT server will publish the message specified in the WillMessage field to the topic indicated in the WillTopic 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 retrieve their values when we work with MQTT tools and MQTT client libraries.
- SessionPresent: If the MQTT server received a connection request with the CleanSession flag set to 1 or true, the value for the SessionPresent flag will be 0 or false because no stored session will be reused. If the CleanSession flag was set to 0 or false in the connection request, the MQTT server will work with a persistent session and the value for the SessionPresent flag will be 1 or true if the server had a persistent session for the client from a previous connection and retrieves it. Otherwise, SessionPresent will be 0 or false. 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 for ReturnCode will be 0. Otherwise, the return code will be different than 0 and the network connection between the client and the server will be closed. The following table shows the possible values for ReturnCode with their meaning.
|0||The connection was accepted|
|1||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|
|2||The connection was refused because the ClientId (client identifier) specified has been rejected|
|3||The connection was refused because the network connection was established but the MQTT service isn’t available|
|4||The connection was refused because the user name or password values are malformed|
|5||The connection was refused because authorization failed|
Gastón C. Hillar has a bachelor’s degree in computer science (graduated with honors), and an MBA (graduated with an outstanding thesis). At present, Gastón is an independent IT consultant and freelance author who is always looking for new adventures around the world. He has been a senior contributing editor at Dr. Dobb’s and has written more than a hundred articles on software development topics. Gastón was also a former Microsoft MVP in technical computing. He has received the prestigious Intel Black Belt Software Developer award eight times. Gastón’s blog is http://csharpmulticore.blogspot.com.