PrevUpHomeNext

Getting Started

This section guides you through the steps to properly configure the mqtt_client to establish a connection with your chosen MQTT Broker.

The mqtt_client does not expose connect functions (nor asynchronous connect functions). Instead, it features a function that will start the Client (see mqtt_client::async_run). All configuration of the mqtt_client must be finalised before invoking mqtt_client::async_run. Upon calling this function, the mqtt_client makes its initial attempt to connect.

The initial step is selecting an appropriate transport protocol for your MQTT connection.

The MQTT protocol relies on an underlying transport protocol that guarantees the orderly and reliable transmission of byte streams between the Client and Server in both directions. Common transport protocols meeting these criteria include TCP/IP, TLS/SSL for secure transmissions, and WebSocket over TCP/IP and TLS/SSL.

MQTT Brokers come in various implementations and support different transport protocols. Therefore, it is important to familiarise yourself with the protocols your chosen Broker supports. Additionally, gather any necessary details, such as certificate authority, client certificate, or private keys, which might be required for establishing a secure connection.

In this example, we choose TCP/IP as the underlying protocol to initialize the mqtt_client.

// Initialize the execution context required to run I/O operations.
boost::asio::io_context ioc;

// Construct the Client with boost::asio::ip::tcp::socket as the underlying stream.
async_mqtt5::mqtt_client<boost::asio::ip::tcp::socket> client(ioc);

The mqtt_client offers a variety of functions for configuring your MQTT connection settings. These functionalities include:

  • Specifying a list of Brokers: You must use this function to assign a list of Brokers that the mqtt_client will try to connect to (see mqtt_client::brokers). The mqtt_client allows for the specification of multiple Brokers for the connections. It is important to ensure that only Brokers belonging to the same cluster are included in this list. Listing Brokers from different clusters may lead to inconsistencies between MQTT Sessions.
  • Setting connection Credentials: Set the authentication details (Client Identifier, User Name, Password) (see mqtt_client::credentials).
  • Configuring Keep Alive Interval: Set the maximum allowed interval between two consecutive transmissions from the Client (see mqtt_client::keep_alive).
  • Assign a custom user-implemented authenticator: The custom authentication will be used for Enhanced Authentication (mqtt_client::authenticator).
  • Defining CONNECT Packet Properties: Specify properties that will be included in the CONNECT packet sent during connection initiation (see mqtt_client::connect_property and mqtt_client::connect_properties).

Firstly, we will specify the Broker we want to connect to using the mqtt_client::brokers function. This can be HiveMQ's public Broker available at broker.hivemq.com:1883. Additionally, we can set the Client Identifier using the mqtt_client::credentials function. This is not mandatory, as some Brokers allow anonymous connections.

After configuring the mqtt_client, we call the mqtt_client::async_run function. This starts the process of establishing a connection with the Broker.

client.brokers(cfg.brokers, cfg.port) // Set the Broker to connect to.
	.credentials(cfg.client_id) // Set the Client Identifier. (optional)
	.async_run(boost::asio::detached); // Start the Client.

It is important to note that these configurations apply to every Broker listed in mqtt_client::brokers. To modify any configuration parameters, you must first stop the mqtt_client using mqtt_client::cancel or mqtt_client::async_disconnect. Afterwards, you can re-apply the configurations and restart the mqtt_client with mqtt_client::async_run.

The mqtt_client initiates a connection with the first Broker from the list of Brokers assigned using mqtt_client::brokers. A single attempt at connecting involves several steps:

  1. Resolving the Broker's hostname.
  2. Creating a TCP connection.
  3. Performing the TLS/SSL Handshake (if applicable).
  4. Performing the WebSocket Handshake (if applicable).
  5. Performing the MQTT handshake. This involves sending the CONNECT packet to the Broker, (if applicable) exchanging AUTH packets (see Enhanced Authentication), and continuing until the Broker sends the CONNACK packet.

The connection is successfully established once the mqtt_client receives a CONNACK packet with Reason Code 0x00 (Success). The attempt fails if any of the following occurs:

  • Any of the steps from 1 to 5 encounters a failure.
  • The mqtt_client does not receive the results of the hostname resolution within 5 seconds.
  • The mqtt_client is unable to complete steps 2 through 5 within 5 seconds.

If this connection attempt is unsuccessful, it proceeds to the next Broker in order, continuing this process until it establishes a connection or exhausts all options without success. Upon reaching the end of the list without a successful connection, the mqtt_client enters a backoff period before making another round of attempts with the entire list. The duration of this backoff period in milliseconds is determined by the formula:

2^(min(retry_count, 4)) * 1000 + jitter

In this formula, retry_count represents the number of complete cycles through the list without a successful connection, and jitter is a randomly chosen value between -500ms to 500ms, intended to prevent synchronised reconnection attempts in scenarios with multiple clients.

After calling mqtt_client::async_run, you can now use the Client according to your application needs. In this case, we will publish a "Hello World!" message to async-mqtt5/test topic with Quality of Service 0 (at most once) using the mqtt_client::async_publish function.

client.async_publish<async_mqtt5::qos_e::at_most_once>(
	"async-mqtt5/test", "Hello world!",
	async_mqtt5::retain_e::yes, async_mqtt5::publish_props {},
	[&client](async_mqtt5::error_code ec) {
		std::cout << ec.message() << std::endl;

		// Disconnnect the Client.
		client.async_disconnect(boost::asio::detached);
	}
);

You can find the full program listing for this chapter at the link below:

Additional "Hello World!" examples for different underlying transport protocols can be found here:

If you encounter configuration or connection issues, you can use our logging mechanism to debug problems. The mqtt_client introduces a LoggerType as its third template parameter, which specifies the type used for logging events within the mqtt_client.

The Async.MQTT5 library provides a built-in logger implementation that outputs operation results to stderr. This logger outputs detailed information about each step in the connection process, including DNS resolution, TCP connection, TLS handshake, WebSocket handshake, and MQTT handshake. To enable this functionality, construct the mqtt_client with an instance of this logger class:

// Construct the Client with boost::asio::ip::tcp::socket as the underlying stream and enabled logging.
// Since we are not establishing a secure connection, set the TlsContext template parameter to std::monostate.
async_mqtt5::mqtt_client<
	boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, async_mqtt5::logger
> client(ioc, {} /* tls_context */, async_mqtt5::logger(async_mqtt5::log_level::info));

PrevUpHomeNext