Skip to content
Takatoshi Kondo edited this page Dec 7, 2020 · 9 revisions

Three clients

mqtt_cpp has three clients.

sync_client

sync_client can use synchronous interface. The synchronous interfaces are not explicitly named. For example, publish() is a synchronous interface. Synchronous interface uses underlying synchronous interface e.g. Boost.Asio write(). Synchronous interface function returns when the data is written into the socket. So you can destroy the data you passed to the interface after the function is returned.

automatically sending messages are send synchronously.

connect error handling

The connect() function do many things.

  1. Setup TCP connection.
  2. Setup TLS connection (optional)
  3. Setup WebSocket connection (optional)
  4. Send MQTT connect packet synchronously
  5. MQTT connack packet is received asynchronously
  • Until v7.0.0, if error occurred at the step 1 to 5 and after the step 5, then error handler is called.
  • Since v8.0.0,
    • if error occurred at the step 1 to 4,
      • if connect() is called with boost::system::error_code argument then set the error code to the argument.
      • Otherwise the exception that holds error_code is thrown.
    • if error occurred after the step 5, then error handler is called.

async_client

async_client can use asynchronous interface. The asynchronous interfaces are explicitly named. For example, async_publish() is a asynchronous interface. Synchronous interface uses underlying asynchronous interface e.g. Boost.Asio async_write(). Asynchronous interface function returns immediately. If you use std::string for topic and payload, the lifetime of them are managed by mqtt_cpp. But if you use as::const_buffer, you need to care the lifetime of the data you passed to the interface while mqtt_cpp is using the data.

How to know that? If the asynchronous function has the parameter named life_keeper, then pass your life-keeping object such as std::shared_ptr to it. The type of life_keeper is mqtt::any you can pass not only std::shared_ptr but also std::pair or std::tuple of std::shared_ptrs.

If the asynchronous function doesn't have the parameter named life_keeper, but has the parameter named async_handler, then capture your life-keeping object into the lambda function that you pass as async_handler.

automatically sending messages are send synchronously or asynchronously depends on their type.

connect error handling

The async_connect() function do many things.

  1. Setup TCP connection.
  2. Setup TLS connection (optional)
  3. Setup WebSocket connection (optional)
  4. Send MQTT connect packet asynchronously
  5. MQTT connack packet is received asynchronously
  • Until v7.0.0, if error occurred at the step 1 to 5 and after the step 5, then error handler is called.

  • Since v8.0.0,

    • if error occurred at the step 1 to 4,
      • if async_connect is called with async_handler, then async_handler is called with boost::system::error_code`.
      • Otherwise, do nothing.
    • if error occurred after the step 5, then error handler is called.
  • automatically sending messages#after-connack are send synchronously.

    • It should be asynchronously in the future. The messages are publish and/or pubrel. They are sent after connack message received and before connack handler is called. There is no chance to interrupt message sending API call. So it is safe.
  • automatically sending messages#publish-response are send asynchronously.

  • automatically sending messages#ping are send asynchronously. (since #267 merged)

client (expert only)

  • client can send messages synchronously and/or asynchronously. It is very flexible but user need to care about the following rule.
    • When async message is sending, async API is called but async_handler is not invoked yet, you cannot call sync APIs. It causes send buffer overwrite problem. See the following table.
sync sending async sending
sync call never happen dangerous
async call never happen no problem