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/4 board, an Intel Joule board, an android, 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 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.
The MQTT server is the central hub of the publish/subscribe model we previously analyzed. The MQTT server is responsible for 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.
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.
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.
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.
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.
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.
The protocol level value indicates the MQTT protocol version that the MQTT client requests the MQTT server to use.
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.
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.
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.
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.