'Is waiting for action completion in MQTT async_client necessary?

I am working on an cpp MQTT async_client utilizing the paho library. I am trying to fully understand the workings of the asynchronous client, but I am not sure how to correctly utilize the features.

As I understand it, messages with QoS > 0 follow a handshake procedure specified by the standard. The delivery to the server is regarded as complete if either PUBACK (QoS 1) or PUBCOMP (QoS 2) has been received. All of this seems to be handled by the library. The user can interact with the client either through callbacks or through tokens associated with specific actions (e.g. publish).

I have the following questions regarding these tools:

  1. The user can either register a mqtt::iaction_listener callback to an action that is invoked when the action fails and/or succeeds. Simultaneously, there exists a callback when the last message of a handshake has been successfully received (PUBACK and PUBCOMP, respectively). Are the success callbacks not redundant?
  2. Waiting for message tokens to complete in an asynchronous client does not make sense for me. If I wait for message to be published, I block the sending thread. Surely, I could use separate thread for waiting, but that defeats the purpose of asynchronous clients. So do I just omit the wait, especially when sending messages in rapid succession? (see code below)

Test client code:

#include <iostream>
#include <cstdlib>
#include <string>
#include <cstring>
#include <cctype>
#include <thread>
#include <chrono>
#include "mqtt/async_client.h"

const std::string SERVER_ADDRESS("tcp://localhost:1883");
const std::string CLIENT_ID("client1");
const std::string TOPIC("hello");


class Callback
    : public virtual mqtt::callback
{
    // the mqtt client
    mqtt::async_client& cli_;

    void delivery_complete(mqtt::delivery_token_ptr tok) override
    {
        std::cout << "delivery_complete for token: " << tok->get_message_id() << std::endl;
    }

public:
    Callback(mqtt::async_client& cli)
        : cli_(cli) {}
};


int main(int argc, char* argv[])
{
    mqtt::async_client cli(SERVER_ADDRESS, CLIENT_ID);

    mqtt::connect_options connOpts;
    connOpts.set_clean_session(false);

    Callback cb(cli);
    cli.set_callback(cb);

    // Connect; waiting makes sense here as publishing without a connection is nonsense
    try {
        cli.connect(connOpts);
    }
    catch (const mqtt::exception& exc) {
        std::cerr << "\nERROR: Unable to connect to MQTT server: '"
            << SERVER_ADDRESS << "'" << exc << std::endl;
        return 1;
    }

    // Press 'm' to send messages or 'q' to exit
    while (true)
    {
        char c = std::tolower(std::cin.get());

        if (c == 'q') {
            break;
        }

        else if (c == 'm')
        {
            for (int i = 0; i < 10; ++i)
            {
                mqtt::message_ptr pubmsg = mqtt::make_message(TOPIC, "TESTMSG");
                pubmsg->set_qos(1);
                auto tok = cli.publish(pubmsg);

                tok->wait();     // how is this done correctly with QoS > 0 ?
            }
        }
    }

    // Disconnect
    try {
        cli.disconnect()->wait();
        std::cout << "OK" << std::endl;
    }
    catch (const mqtt::exception& exc) {
        std::cerr << exc << std::endl;
        return 1;
    }

    return 0;
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source