### Configure MQTT Connection Parameters and Start Client Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/getting_started Configures the mqtt_client with broker details, client identifier, and optional connection properties like session expiry interval. It then initiates the connection process using async_run. ```cpp client.brokers(cfg.brokers, cfg.port) // Set the Broker to connect to. .credentials(cfg.client_id) // Set the Client Identifier. (optional) .connect_property(boost::mqtt5::prop::session_expiry_interval, 60) // optional .async_run(boost::asio::detached); // Start the Client. ``` -------------------------------- ### Initializing Boost.MQTT5 Client with Logging Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/getting_started Shows how to construct an `mqtt_client` with the built-in logger enabled. This logger outputs detailed information about the connection process to stderr, aiding in debugging. ```cpp // 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. boyoost::mqtt5::mqtt_client< boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger > client(ioc, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::info)); ``` -------------------------------- ### Publishing a Message with Boost.MQTT5 Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/getting_started Demonstrates how to publish a message with Quality of Service 0 to a specified topic using the `mqtt_client::async_publish` function. It includes a callback to handle the result and disconnect the client. ```cpp client.async_publish( "boost-mqtt5/test", "Hello world!", boost::mqtt5::retain_e::yes, boost::mqtt5::publish_props {}, [&client](boost::mqtt5::error_code ec) { std::cout << ec.message() << std::endl; // Disconnnect the Client. client.async_disconnect(boost::asio::detached); } ); ``` -------------------------------- ### Initialize MQTT Client with TCP/IP Transport Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/getting_started Initializes the Boost.Asio io_context and constructs an mqtt_client using TCP/IP as the underlying transport protocol. This is the first step before configuring connection parameters. ```cpp // 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. boost::mqtt5::mqtt_client client(ioc); ``` -------------------------------- ### Connect and Publish Hello World over WebSocket/TCP with Boost.MQTT5 Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/hello_world_over_websocket_tcp This snippet demonstrates connecting a Boost.MQTT5 client to a specified broker using WebSocket/TCP. It configures the client with necessary headers, sets broker details and client ID, and then asynchronously publishes a 'Hello World!' message. The example includes optional logging and handles the connection and publish operations using Boost.Asio. It requires Boost.MQTT5, Boost.Asio, and Boost.Beast libraries. ```cpp #include #include #include #include // WebSocket traits #include #include #include #include #include #include struct config { std::string brokers = "broker.hivemq.com/mqtt"; // Path example: localhost/mqtt uint16_t port = 8000; // 8083 is the default Webscoket/TCP MQTT port. However, HiveMQ's public broker uses 8000 instead. std::string client_id = "boost_mqtt5_tester"; }; int main(int argc, char** argv) { config cfg; if (argc == 4) { cfg.brokers = argv[1]; cfg.port = uint16_t(std::stoi(argv[2])); cfg.client_id = argv[3]; } boost::asio::io_context ioc; // Construct the Client with WebSocket/TCP as the underlying stream and enabled logging. // Since we are not establishing a secure connection, set the TlsContext template parameter to std::monostate. boost::mqtt5::mqtt_client< boost::beast::websocket::stream, std::monostate, boost::mqtt5::logger > client(ioc, {}, boost::mqtt5::logger(boost::mqtt5::log_level::info)); // If you want to use the Client without logging, initialise it with the following line instead. //boost::mqtt5::mqtt_client> client(ioc); client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. .credentials(cfg.client_id) // Set the Client Identifier. (optional) .async_run(boost::asio::detached); // Start the Client. client.async_publish( "boost-mqtt5/test", "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); } ); ioc.run(); } ``` -------------------------------- ### MQTT 5 Client Setup and Message Handling (C++) Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/receiver This snippet demonstrates setting up an MQTT 5 client using Boost.Asio, publishing messages, subscribing to topics, and handling received messages asynchronously via coroutines. It includes client cancellation and error handling. ```cpp // After we are done with publishing all the messages, cancel the timer and the Client. // Alternatively, use mqtt_client::async_disconnect. client.cancel(); }); // Spawn the coroutine. co_spawn( ioc, subscribe_and_receive(cfg, client), [](std::exception_ptr e) { if (e) std::rethrow_exception(e); } ); // Start the execution. ioc.run(); } ``` -------------------------------- ### MQTT Publisher with Boost.MQTT.5 and Boost.Asio Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/publisher This C++ code snippet demonstrates a basic MQTT publisher using the Boost.MQTT.5 library. It connects to a specified broker, publishes sensor readings at regular intervals, and handles connection and publish operations asynchronously. The example requires Boost.Asio and Boost.MQTT.5 libraries. It takes broker address, port, and client ID as command-line arguments. ```cpp #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct config { std::string brokers = "broker.hivemq.com"; uint16_t port = 1883; std::string client_id = "boost_mqtt5_tester"; }; // Modified completion token that will prevent co_await from throwing exceptions. constexpr auto use_nothrow_awaitable = boost::asio::as_tuple(boost::asio::deferred); // client_type with logging enabled using client_type = boost::mqtt5::mqtt_client< boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger >; // client_type without logging //using client_type = boost::mqtt5::mqtt_client; int next_sensor_reading() { srand(static_cast(std::time(0))); return rand() % 100; } boost::asio::awaitable publish_sensor_readings( const config& cfg, client_type& client, boost::asio::steady_timer& timer ) { // Configure the Client. // It is mandatory to call brokers() and async_run() to configure the Brokers to connect to and start the Client. client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. .credentials(cfg.client_id) // Set the Client Identifier. (optional) .async_run(boost::asio::detached); // Start the Client. for (;;) { // Get the next sensor reading. auto reading = std::to_string(next_sensor_reading()); // Publish the sensor reading with QoS 1. auto&& [ec, rc, props] = co_await client.async_publish( "boost-mqtt5/test" /* topic */, reading /* payload */, boost::mqtt5::retain_e::no, boost::mqtt5::publish_props {}, use_nothrow_awaitable ); // An error can occur as a result of: // a) wrong publish parameters // b) mqtt_client::cancel is called while the Client is publishing the message // resulting in cancellation. if (ec) { std::cout << "Publish error occurred: " << ec.message() << std::endl; break; } // Reason code is the reply from the server presenting the result of the publish operation. std::cout << "Result of publish request: " << rc.message() << std::endl; if (!rc) std::cout << "Published sensor reading: " << reading << std::endl; // Wait 5 seconds before publishing the next reading. timer.expires_after(std::chrono::seconds(5)); auto&& [tec] = co_await timer.async_wait(use_nothrow_awaitable); // An error occurred if we cancelled the timer. if (tec) break; } co_return; } int main(int argc, char** argv) { config cfg; if (argc == 4) { cfg.brokers = argv[1]; cfg.port = uint16_t(std::stoi(argv[2])); cfg.client_id = argv[3]; } // Initialise execution context. boost::asio::io_context ioc; // Initialise the Client to connect to the Broker over TCP. client_type client(ioc, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::info)); // Initialise the timer. boost::asio::steady_timer timer(ioc); // Set up signals to stop the program on demand. boost::asio::signal_set signals(ioc, SIGINT, SIGTERM); signals.async_wait([&client, &timer](boost::mqtt5::error_code /* ec */, int /* signal */) { // After we are done with publishing all the messages, cancel the timer and the Client. // Alternatively, use mqtt_client::async_disconnect. timer.cancel(); client.cancel(); }); // Spawn the coroutine. co_spawn( ioc.get_executor(), publish_sensor_readings(cfg, client, timer), [](std::exception_ptr e) { if (e) std::rethrow_exception(e); } ); // Start the execution. ioc.run(); } ``` -------------------------------- ### Boost.MQTT5 Multiflight Client Example in C++ Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/multiflight_client This C++ code demonstrates how to use the Boost.MQTT5 library to create a client that can handle multiple concurrent requests. It sets up the client, connects to a broker, and publishes messages asynchronously with different quality of service levels. The example utilizes Boost.Asio for asynchronous operations and signal handling for graceful disconnection. ```cpp #include #include #include #include #include #include #include #include #include #include struct config { std::string brokers = "broker.hivemq.com"; uint16_t port = 1883; std::string client_id = "boost_mqtt5_tester"; }; int main(int argc, char** argv) { config cfg; if (argc == 4) { cfg.brokers = argv[1]; cfg.port = uint16_t(std::stoi(argv[2])); cfg.client_id = argv[3]; } boost::asio::io_context ioc; // 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. boost::mqtt5::mqtt_client< boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger > client(ioc, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::info)); client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. .credentials(cfg.client_id) // Set the Client Identifier. (optional) .async_run(boost::asio::detached); // Start the client. // Publish with QoS 2 five times in a row without waiting for the handler // of the previous async_publish call to be invoked. for (auto i = 1; i <= 5; ++i) client.async_publish( "boost-mqtt5/test", "Hello world!", boost::mqtt5::retain_e::no, boost::mqtt5::publish_props {}, [i](boost::mqtt5::error_code ec, boost::mqtt5::reason_code rc, boost::mqtt5::pubcomp_props) { std::cout << "Publish number " << i << " completed with: " << std::endl; std::cout << "\t ec: " << ec.message() << std::endl; std::cout << "\t rc: " << rc.message() << std::endl; } ); // We can stop the Client by using signals. boost::asio::signal_set signals(ioc, SIGINT, SIGTERM); signals.async_wait([&client](boost::mqtt5::error_code, int) { client.async_disconnect(boost::asio::detached); }); ioc.run(); } ``` -------------------------------- ### Configure and Publish MQTT.5 Message with QoS 0 Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/intro This C++ code configures an MQTT.5 client using Boost.Asio and Boost.MQTT.5. It connects to a specified broker with credentials, publishes a 'Hello World!' message on a given topic with QoS 0, and then disconnects. The example requires Boost.Asio and Boost.MQTT.5 libraries. ```cpp #include #include #include #include #include #include int main() { boost::asio::io_context ioc; boost::mqtt5::mqtt_client c(ioc); c.brokers("", 1883) .credentials("", "", "") .async_run(boost::asio::detached); c.async_publish( "", "Hello world!", boost::mqtt5::retain_e::no, boost::mqtt5::publish_props {}, [&c](boost::mqtt5::error_code ec) { std::cout << ec.message() << std::endl; c.async_disconnect(boost::asio::detached); // disconnect and close the Client } ); ioc.run(); } ``` -------------------------------- ### C++ MQTT5 Hello World with Callbacks Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/hello_world_in_multithreaded_env This C++ code demonstrates publishing a 'Hello World' message using Boost.MQTT5 in a multithreaded environment. It utilizes Boost.Asio for asynchronous operations, thread pools for concurrency, and callbacks for handling publish acknowledgments. The example requires Boost.Asio and Boost.MQTT5 libraries. ```cpp #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct config { std::string brokers = "broker.hivemq.com"; uint16_t port = 1883; std::string client_id = "boost_mqtt5_tester"; }; int main(int argc, char** argv) { config cfg; if (argc == 4) { cfg.brokers = argv[1]; cfg.port = uint16_t(std::stoi(argv[2])); cfg.client_id = argv[3]; } // Create a thread pool with 4 threads. boost::asio::thread_pool tp(4); // Create an explicit strand from thread_pool's executor. // The strand guarantees a serialised handler execution regardless of the // number of threads running in the thread_pool. boost::asio::strand strand = boost::asio::make_strand(tp.get_executor()); // Create the Client with the explicit strand as the default associated executor. boost::mqtt5::mqtt_client< boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger > client(strand, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::info)); // Configure the client. client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. .credentials(cfg.client_id); // Set the Client Identifier. (optional) // Start the Client. // The async_run function call must be posted/dispatched to the strand. boost::asio::dispatch( boost::asio::bind_executor( strand, [&client, &strand, &cfg] { // Considering that the default associated executor of all completion handlers is the strand, // it is not necessary to explicitly bind it to async_run or other async_xxx's handlers. client.async_run(boost::asio::detached); // Start the Client. } ) ); // The async_publish function call must be posted/dispatched to the strand. // The associated executor of async_publish's completion handler must be the same strand. boost::asio::dispatch( boost::asio::bind_executor( strand, [&client, &strand, &cfg] { assert(strand.running_in_this_thread()); client.async_publish( "boost-mqtt5/test", "Hello World!", boost::mqtt5::retain_e::no, boost::mqtt5::publish_props {}, // You may bind the strand to this handler, but it is not necessary // as the strand is already the default associated handler. [&client, &strand]( boost::mqtt5::error_code ec, boost::mqtt5::reason_code rc, boost::mqtt5::puback_props props ) { assert(strand.running_in_this_thread()); std::cout << ec.message() << std::endl; std::cout << rc.message() << std::endl; // Stop the Client. client.cancel(); } ); } ) ); tp.join(); return 0; } ``` -------------------------------- ### Connect and Publish "Hello World" via Websocket/TLS (C++) Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/hello_world_over_websocket_tls Sets up a Boost.MQTT5 client to connect to a specified broker using Websocket and TLS. It configures the TLS context, initializes the client with logging, publishes a "Hello World!" message to the 'boost-mqtt5/test' topic, and then disconnects. The connection details (broker address, port, client ID) can be provided via command-line arguments. ```cpp #include #include #include #include // WebSocket and OpenSSL traits #include #include #include #include #include #include #include struct config { std::string brokers = "broker.hivemq.com/mqtt"; // Path example: localhost/mqtt uint16_t port = 8884; // 8884 is the default Websocket/TLS MQTT port. std::string client_id = "boost_mqtt5_tester"; }; // External customization point. namespace boost::mqtt5 { // Specify that the TLS handshake will be performed as a client. template struct tls_handshake_type> { static constexpr auto client = boost::asio::ssl::stream_base::client; }; // This client uses this function to indicate which hostname it is // attempting to connect to at the start of the handshaking process. template void assign_tls_sni( const authority_path& ap, boost::asio::ssl::context& /*ctx*/, boost::asio::ssl::stream& stream ) { SSL_set_tlsext_host_name(stream.native_handle(), ap.host.c_str()); } } // end namespace boost::mqtt5 int main(int argc, char** argv) { config cfg; if (argc == 4) { cfg.brokers = argv[1]; cfg.port = uint16_t(std::stoi(argv[2])); cfg.client_id = argv[3]; } boost::asio::io_context ioc; // TLS context that the underlying SSL stream will use. // The purpose of the context is to allow us to set up TLS/SSL-related options. // See SSL for more information and options. boost::asio::ssl::context context(boost::asio::ssl::context::tls_client); // Set up the TLS context. // This step is highly dependent on the specific requirements of the Broker you are connecting to. // Each broker may have its own standards and expectations for establishing a secure TLS/SSL connection. // This can include verifying certificates, setting up private keys, PSK authentication, and others. // Construct the Client with WebSocket/SSL as the underlying stream // with boost::asio::ssl::context as the _TlsContext_ type and enabled logging. boost::mqtt5::mqtt_client< boost::beast::websocket::stream>, boost::asio::ssl::context, boost::mqtt5::logger > client(ioc, std::move(context), boost::mqtt5::logger(boost::mqtt5::log_level::info)); // If you want to use the Client without logging, initialise it with the following line instead. //boost::mqtt5::mqtt_client< // boost::beast::websocket::stream>, // boost::asio::ssl::context //> client(ioc, std::move(context)); client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. .credentials(cfg.client_id) // Set the Client Identifier. (optional) .async_run(boost::asio::detached); // Start the Client. client.async_publish( "boost-mqtt5/test", "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); } ); ioc.run(); } ``` -------------------------------- ### Connect and Publish Hello World using Boost.MQTT.5 and TCP/IP Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/hello_world_over_tcp This C++ code snippet demonstrates connecting a Boost.MQTT.5 client to an MQTT broker over TCP/IP, publishing a 'Hello World!' message with QoS level 'at most once' and retain flag set to 'yes', and then disconnecting. It utilizes Boost.Asio for asynchronous operations and includes optional client configuration via command-line arguments. The example requires Boost libraries for Asio and MQTT.5. ```cpp #include #include #include #include #include #include #include #include struct config { std::string brokers = "broker.hivemq.com"; uint16_t port = 1883; // 1883 is the default TCP MQTT port. std::string client_id = "boost_mqtt5_tester"; }; int main(int argc, char** argv) { config cfg; if (argc == 4) { cfg.brokers = argv[1]; cfg.port = uint16_t(std::stoi(argv[2])); cfg.client_id = argv[3]; } boost::asio::io_context ioc; // 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. boost::mqtt5::mqtt_client< boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger > client(ioc, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::info)); // If you want to use the Client without logging, initialise it with the following line instead. //boost::mqtt5::mqtt_client client(ioc); client.brokers(cfg.brokers, cfg.port) // Set the Broker to connect to. .credentials(cfg.client_id) // Set the Client Identifier. (optional) .connect_property(boost::mqtt5::prop::session_expiry_interval, 60) // optional .async_run(boost::asio::detached); // Start the Client. client.async_publish( "boost-mqtt5/test", "Hello world!", boost::mqtt5::retain_e::yes, boost::mqtt5::publish_props {}, [&client](boost::mqtt5::error_code ec) { std::cout << ec.message() << std::endl; // Disconnnect the Client. client.async_disconnect(boost::asio::detached); } ); ioc.run(); } ``` -------------------------------- ### Publish Hello World with MQTT5 Coroutines Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/hello_world_in_coro_multithreaded_env Publishes a 'Hello World' message using Boost.MQTT5 and Boost.Asio coroutines within a multithreaded environment. It configures the MQTT client, connects to a broker, publishes a message with QoS level 1, and then disconnects. The coroutine is executed within a strand to ensure serialized handler execution, preventing race conditions in the multithreaded pool. Dependencies include Boost.Asio and Boost.MQTT5 libraries. ```cpp #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct config { std::string brokers = "broker.hivemq.com"; uint16_t port = 1883; std::string client_id = "boost_mqtt5_tester"; }; // client_type with logging enabled using client_type = boost::mqtt5::mqtt_client< boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger >; // client_type without logging //using client_type = boost::mqtt5::mqtt_client; // Modified completion token that will prevent co_await from throwing exceptions. constexpr auto use_nothrow_awaitable = boost::asio::as_tuple(boost::asio::deferred); boost::asio::awaitable publish_hello_world( const config& cfg, client_type& client, const boost::asio::strand& strand ) { // Confirmation that the coroutine running in the strand. assert(strand.running_in_this_thread()); // All these function calls will be executed by the strand that is executing the coroutine. // All the completion handler's associated executors will be that same strand // because the Client was constructed with it as the default associated executor. client.brokers(cfg.brokers, cfg.port) .credentials(cfg.client_id) .async_run(boost::asio::detached); auto&& [ec, rc, puback_props] = co_await client.async_publish( "boost-mqtt5/test" , "Hello world!" , boost::mqtt5::retain_e::no, boost::mqtt5::publish_props {}, use_nothrow_awaitable); co_await client.async_disconnect(use_nothrow_awaitable); co_return; } int main(int argc, char** argv) { config cfg; if (argc == 4) { cfg.brokers = argv[1]; cfg.port = uint16_t(std::stoi(argv[2])); cfg.client_id = argv[3]; } boost::asio::thread_pool tp(4); boost::asio::strand strand = boost::asio::make_strand(tp.get_executor()); client_type client(strand, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::info)); co_spawn( strand, publish_hello_world(cfg, client, strand), [](std::exception_ptr e) { if (e) std::rethrow_exception(e); } ); tp.join(); return 0; } ``` -------------------------------- ### Create MQTT Client with Strand Executor in Boost ASIO Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/asio_compliance/executors Demonstrates constructing a mqtt_client with a strand executor from an io_context. The strand becomes the default executor for all asynchronous operations like async_publish. The example shows how to verify that operations execute within the strand's thread context and manage client lifecycle with async_run and cancel operations. ```C++ int main() { boost::asio::io_context ioc; // Construct the Client with a strand. auto strand = boost::asio::make_strand(ioc.get_executor()); boost::mqtt5::mqtt_client client(strand); client.brokers("", 1883) .async_run(boost::asio::detached); // This asynchronous operation will use the default associated executor, // which is the strand with which the Client is constructed. client.async_publish( "", "Hello world!", boost::mqtt5::retain_e::no, boost::mqtt5::publish_props {}, [&client, &strand](boost::mqtt5::error_code /* ec */) { assert(strand.running_in_this_thread()); client.cancel(); } ); ioc.run(); } ``` -------------------------------- ### MQTT5 Client Receiver: Subscribe and Receive Messages Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/receiver This C++ code snippet demonstrates a complete MQTT5 client receiver. It configures the client, subscribes to a topic ('test') with specific options (QoS 2, etc.), and then enters a loop to continuously receive and process incoming messages. It handles session expiration by re-subscribing and includes basic error handling for subscription and receiving operations. Dependencies include Boost.ASIO and Boost.MQTT5. ```cpp #include #include #include #include #include #include #include #include #include #include #include #include #include struct config { std::string brokers = "broker.hivemq.com"; uint16_t port = 1883; std::string client_id = "boost_mqtt5_tester"; }; // Modified completion token that will prevent co_await from throwing exceptions. constexpr auto use_nothrow_awaitable = boost::asio::as_tuple(boost::asio::deferred); // client_type with logging enabled using client_type = boost::mqtt5::mqtt_client< boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger >; // client_type without logging //using client_type = boost::mqtt5::mqtt_client; boost::asio::awaitable subscribe(client_type& client) { // Configure the request to subscribe to a Topic. boost::mqtt5::subscribe_topic sub_topic = boost::mqtt5::subscribe_topic{ "test" /* topic */, boost::mqtt5::subscribe_options { boost::mqtt5::qos_e::exactly_once, // All messages will arrive at QoS 2. boost::mqtt5::no_local_e::no, // Forward message from Clients with same ID. boost::mqtt5::retain_as_published_e::retain, // Keep the original RETAIN flag. boost::mqtt5::retain_handling_e::send // Send retained messages when the subscription is established. } }; // Subscribe to a single Topic. auto&& [ec, sub_codes, sub_props] = co_await client.async_subscribe( sub_topic, boost::mqtt5::subscribe_props {}, use_nothrow_awaitable ); // Note: you can subscribe to multiple Topics in one mqtt_client::async_subscribe call. // An error can occur as a result of: // a) wrong subscribe parameters // b) mqtt_client::cancel is called while the Client is in the process of subscribing if (ec) std::cout << "Subscribe error occurred: " << ec.message() << std::endl; else std::cout << "Result of subscribe request: " << sub_codes[0].message() << std::endl; co_return !ec && !sub_codes[0]; // True if the subscription was successfully established. } boost::asio::awaitable subscribe_and_receive( const config& cfg, client_type& client ) { // Configure the Client. // It is mandatory to call brokers() and async_run() to configure the Brokers to connect to and start the Client. client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. .credentials(cfg.client_id) // Set the Client Identifier. (optional) .async_run(boost::asio::detached); // Start the client. // Before attempting to receive an Application Message from the Topic we just subscribed to, // it is advisable to verify that the subscription succeeded. // It is not recommended to call mqtt_client::async_receive if you do not have any // subscription established as the corresponding handler will never be invoked. if (!(co_await subscribe(client))) co_return; for (;;) { // Receive an Appplication Message from the subscribed Topic(s). auto&& [ec, topic, payload, publish_props] = co_await client.async_receive(use_nothrow_awaitable); if (ec == boost::mqtt5::client::error::session_expired) { // The Client has reconnected, and the prior session has expired. // As a result, any previous subscriptions have been lost and must be reinstated. if (co_await subscribe(client)) continue; else break; } else if (ec) break; std::cout << "Received message from the Broker" << std::endl; std::cout << "\t topic: " << topic << std::endl; std::cout << "\t payload: " << payload << std::endl; } co_return; } int main(int argc, char** argv) { config cfg; if (argc == 4) { cfg.brokers = argv[1]; cfg.port = uint16_t(std::stoi(argv[2])); cfg.client_id = argv[3]; } // Initialise execution context. boost::asio::io_context ioc; // Initialise the Client to connect to the Broker over TCP. client_type client(ioc, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::info)); // Set up signals to stop the program on demand. boost::asio::signal_set signals(ioc, SIGINT, SIGTERM); signals.async_wait([&client](boost::mqtt5::error_code /* ec */, int /* signal */) { ``` -------------------------------- ### C++ MQTT Client with Time Constraint using Parallel Group Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/timeout_with_parallel_group This C++ code snippet demonstrates how to use the Boost.MQTT.5 library to subscribe to an MQTT topic and attempt to receive a message within a 5-second time limit. It employs boost::asio::experimental::parallel_group to manage the concurrent operations of a steady_timer and the client's async_receive. The example requires Boost.ASIO and Boost.MQTT.5 libraries. It takes optional command-line arguments for broker address, port, and client ID. ```cpp #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct config { std::string brokers = "broker.hivemq.com"; uint16_t port = 1883; std::string client_id = "boost_mqtt5_tester"; }; int main(int argc, char** argv) { config cfg; if (argc == 4) { cfg.brokers = argv[1]; cfg.port = uint16_t(std::stoi(argv[2])); cfg.client_id = argv[3]; } boost::asio::io_context ioc; // 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. boost::mqtt5::mqtt_client< boost::asio::ip::tcp::socket, std::monostate /* TlsContext */, boost::mqtt5::logger > client(ioc, {} /* tls_context */, boost::mqtt5::logger(boost::mqtt5::log_level::info)); // If you want to use the Client without logging, initialise it with the following line instead. //boost::mqtt5::mqtt_client client(ioc); // Construct the timer. boost::asio::steady_timer timer(ioc, std::chrono::seconds(5)); client.brokers(cfg.brokers, cfg.port) // Broker that we want to connect to. .credentials(cfg.client_id) // Set the Client Identifier. (optional) .async_run(boost::asio::detached); // Start the Client. // Subscribe to a Topic. client.async_subscribe( { "test" /* Topic */}, boost::mqtt5::subscribe_props {}, [](boost::mqtt5::error_code ec, std::vector rcs, boost::mqtt5::suback_props) { std::cout << "[subscribe ec]: " << ec.message() << std::endl; std::cout << "[subscribe rc]: " << rcs[0].message() << std::endl; } ); // Create a parallel group to wait up to 5 seconds to receive a message // using client.async_receive(...). boost::asio::experimental::make_parallel_group( timer.async_wait(boost::asio::deferred), client.async_receive(boost::asio::deferred) ).async_wait( boost::asio::experimental::wait_for_one(), [&client]( std::array ord, // Completion order boost::mqtt5::error_code /* timer_ec */, // timer.async_wait(...) handler signature // client.async_receive(...) handler signature boost::mqtt5::error_code receive_ec, std::string topic, std::string payload, boost::mqtt5::publish_props /* props */ ) { if (ord[0] == 1) { std::cout << "Received a message!" << std::endl; std::cout << "[receive ec]: " << receive_ec.message() << std::endl; std::cout << "[receive topic]: " << topic << std::endl; std::cout << "[receive payload]: " << payload << std::endl; } else std::cout << "Timed out! Did not receive a message within 5 seconds." << std::endl; client.cancel(); } ); ioc.run(); } ``` -------------------------------- ### Start MQTT5 Client with async_run - C++ Source: https://www.boost.org/doc/libs/latest/libs/mqtt5/doc/html/mqtt5/ref/boost__mqtt5__mqtt_client/async_run Template method that initiates the MQTT5 client asynchronously. The method accepts an optional completion token parameter and returns a deduced type based on the token. The handler is invoked with a boost::mqtt5::error_code when the operation completes, is cancelled via async_disconnect/cancel, or encounters non-recoverable errors. Supports terminal cancellation type. ```cpp template< typename _CompletionToken_ = typename asio::default_completion_token::type> decltype(auto) async_run( CompletionToken&& token = {}); ```