Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Disconnecting the Client

The mqtt_client remains active until it is either destroyed or explicitly stopped. In idle mode, the mqtt_client periodically sends PINGREQ to the Broker to maintain a stable connection.

The proper way to stop the mqtt_client is by calling either mqtt_client::cancel or mqtt_client::async_disconnect. Invoking mqtt_client::cancel results in the mqtt_client closing the connection to the Broker and cancelling all outstanding asynchronous operations. On the other hand, mqtt_client::async_disconnect will first attempt to send a DISCONNECT packet [4] to the Broker to notify it about the reason for disconnection, then close the connection and cancel all outstanding asynchronous operations (equal effect as mqtt_client::cancel).

[Important] Important

Regardless of the method used to stop the mqtt_client, it is recommended to ensure that all the previous asynchronous operations are completed. Otherwise, they will be cancelled.

mqtt_client::cancel performs an immediate local shutdown. mqtt_client::async_disconnect performs a graceful MQTT shutdown if it successfully sends the DISCONNECT packet, followed by the same local cleanup. In both cases, operations still pending on that run complete with boost::asio::error::operation_aborted and the Client's resources are released. If the mqtt_client was the only source of work, the execution context (boost::asio::io_context) will stop due to a lack of work.

[Note] Note

The mqtt_client's destructor will also call mqtt_client::cancel.

Calls made after stopping the Client

Both mqtt_client::cancel and mqtt_client::async_disconnect immediately leave the mqtt_client object in a stopped, reusable state. Communication operations initiated through that object after either call complete with boost::asio::error::operation_aborted until mqtt_client::async_run is invoked again. They are not queued for a later restart.

The operations that belonged to the previous run continue only for as long as needed to shut that run down. mqtt_client::cancel cancels them immediately. mqtt_client::async_disconnect instead keeps the previous connection alive for up to 5 seconds while it attempts to send the DISCONNECT packet. A later call to mqtt_client::cancel applies to the current state of the mqtt_client object and does not shorten that already-started disconnect attempt. To cancel the disconnect attempt itself, associate a cancellation slot with the mqtt_client::async_disconnect completion token and emit a terminal cancellation signal.

The following code snippet will showcase a scenario of disconnecting the mqtt_client and its interaction with other asynchronous operations.

Example: immediate disconnection and its impact on outstanding asynchronous operations

The following code snippet is an example of publishing a "Hello World!" message to the Broker with QoS 0, followed by the request to disconnect the mqtt_client.

int main() {
    boost::asio::io_context ioc;

    boost::mqtt5::mqtt_client<boost::asio::ip::tcp::socket> client(ioc);
    client.brokers("<your-mqtt-broker>", 1883)
        .async_run(boost::asio::detached);

    client.async_publish<boost::mqtt5::qos_e::at_most_once>(
        "<topic>", "Hello world!",
        boost::mqtt5::retain_e::no, boost::mqtt5::publish_props {},
        [](boost::mqtt5::error_code ec) {
            std::cout << ec.message() << std::endl;
        }
    );

    client.async_disconnect(boost::asio::detached);

    ioc.run();
}

Suppose the Broker is available and the mqtt_client can successfully connect to it, then the following order of events will unfold:

  1. The Client will successfully establish a connection to the Broker.
  2. The Client will send a DISCONNECT packet with Reason Code 0x00 (Normal Disconnection).

It is important to note that the PUBLISH packet containing the "Hello World!" message will not be transmitted. As outlined in the Packet Ordering in Optimising communication section, mqtt_client::async_publish and mqtt_client::async_disconnect will place their corresponding packets in the queue. However, DISCONNECT packets are prioritised and sent exclusively, ahead of other queued packets. Therefore, the connection will terminate immediately.

If the mqtt_client cannot establish a connection to the Broker, it will be stopped after 5 seconds, which is the amount of time it will spend trying to send the DISCONNECT packet to the Broker before quitting. This timeout mechanism ensures that the mqtt_client does not indefinitely wait to disconnect, preserving resources and maintaining efficient operation.

In this case, the proper way to disconnect would be to call mqtt_client::async_disconnect after the mqtt_client::async_publish has been completed.

client.async_publish<boost::mqtt5::qos_e::at_most_once>(
    "<topic>", "Hello world!",
    boost::mqtt5::retain_e::no, boost::mqtt5::publish_props {},
    [&client](boost::mqtt5::error_code ec) {
        std::cout << ec.message() << std::endl;
        client.async_disconnect(boost::asio::detached);
    }
);

Restarting a mqtt_client is straightforward and requires invoking mqtt_client::async_run. The mqtt_client is configurable again in the interval between stopping and restarting. See Configuring Your MQTT Connection for more information.

Because mqtt_client::async_disconnect immediately makes the mqtt_client object reusable, configuration changes and the next mqtt_client::async_run apply to a new run; they do not affect the connection that is still completing its disconnect attempt.

int main() {
    boost::asio::io_context ioc;

    boost::mqtt5::mqtt_client<boost::asio::ip::tcp::socket> client(ioc);
    client.brokers("<your-mqtt-broker>", 1883)
        .async_run(boost::asio::detached);

    client.async_disconnect(boost::asio::detached);

    // The Client can be reconfigured again.
    client.connect_property(boost::mqtt5::prop::session_expiry_interval, 120)
        .keep_alive(30)
        .async_run(boost::asio::detached); // Restart the Client again.

    // Use the Client...

    ioc.run();
}


[4] The mqtt_client will attempt to send the DISCONNECT packet for 5 seconds. Regardless of the outcome, the connection will be closed.


PrevUpHomeNext