Skip to content
Takatoshi Kondo edited this page May 23, 2019 · 8 revisions

First step to create mqtt client

Include the header file for client.

#include <mqtt_client_cpp.hpp>

Define io_context.

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

Create client.

    auto c = mqtt::make_sync_client(ioc, "test.mosquitto.org", 1883);

Do client settings.

    c->set_client_id("cid1");
    c->set_clean_session(true);

Set handlers.

    c->set_connack_handler(
        [](bool sp, std::uint8_t connack_return_code) {
            return true;
        }
    );
    c->set_close_handler(
        [] {
        }
    );
    c->set_error_handler(
        []
        (boost::system::error_code const& ec) {
        }
    );
    c->set_puback_handler(
        [](std::uint16_t packet_id) {
            return true;
        }
    );
    c->set_pubrec_handler(
        [](std::uint16_t packet_id) {
            return true;
        }
    );
    c->set_pubcomp_handler(
        [](std::uint16_t packet_id) {
            return true;
        }
    );
    c->set_suback_handler(
        [](std::uint16_t packet_id, std::vector<boost::optional<std::uint8_t>> results) {
            return true;
        }
    );
    c->set_publish_handler(
        []
        (std::uint8_t header,
         boost::optional<std::uint16_t> packet_id,
         std::string topic_name,
         std::string contents) {
            return true;
        }
    );

Register connect command.

    c->connect();

Run io_context.

    ioc.run();
}

Actual connection is executed from ioc.run().

Implement the contents of connack_handler. Any mqtt operation need to wait establishing the connection. So connack_handler is the start point of the mqtt operation. In this tutorial, subscribe topic1.

    c->set_connack_handler(
        [&c](bool sp, std::uint8_t connack_return_code) {
            std::cout << "Connack handler called" << std::endl;
            std::cout << "Session Present: " << std::boolalpha << sp << std::endl;
            std::cout << "Connack Return Code: "
                      << mqtt::connect_return_code_to_str(connack_return_code) << std::endl;
            if (connack_return_code == mqtt::connect_return_code::accepted) {
                c->subscribe("topic1", mqtt::qos::at_most_once);
            }
            return true;
        }
    );

Implement the contents of suback_handler. In this tutorial, publish a message test1 to topic1.

    c->set_suback_handler(
        [&c](std::uint16_t packet_id, std::vector<boost::optional<std::uint8_t>> results) {
            std::cout << "suback received. packet_id: " << packet_id << std::endl;
            for (auto const& e : results) {
                if (e) {
                    std::cout << "subscribe success: " << mqtt::qos::to_str(*e) << std::endl;
                }
                else {
                    std::cout << "subscribe failed" << std::endl;
                }
            }
            c->publish_at_most_once("topic1", "test1");
            return true;
        }
    );

Implement the publish_handler. The handler name is little bit confusing. This is a kind of receive message handler.

See the following diagram:

       publish (send)           publish (deliver)
client1 ---------------> broker ------------------> client2

MQTT spec calls both sending client1 to broker and delivering broker to client2 as publish.

mqtt_cpp respects MQTT specification. publish_handler means receiving published message handler.

In this tutorial, print published message and disconnect.

Now, we finished.

Let's compile it.

clang++ -std=c++14 -D MQTT_NO_TLS -I path_to_mqtt_cpp tutorial.cpp -lboost_system -lpthread

This tutorial doesn't use TLS, so defines MQTT_NO_TLS.

Execute the program.

./a.out

Here is my result:

Connack handler called
Session Present: false
Connack Return Code: accepted
suback received. packet_id: 1
subscribe success: at_most_once
publish received. dup: false pos: at_most_once retain: true
topic_name: topic1
contents: helloThere
publish received. dup: false pos: at_most_once retain: false
topic_name: topic1
contents: test1

test.mosquitto.org is public test server. topic1 might has retained data.

In the above result,

publish received. dup: false pos: at_most_once retain: true
topic_name: topic1
contents: helloThere

is retained data.

If you choose an unique topic name, retained data is not appeared.

Here is whole code:

#include <iostream>
#include <mqtt_client_cpp.hpp>

int main() {
    boost::asio::io_context ioc;
    auto c = mqtt::make_sync_client(ioc, "test.mosquitto.org", 1883);

    c->set_client_id("cid1");
    c->set_clean_session(true);

    c->set_connack_handler(
        [&c](bool sp, std::uint8_t connack_return_code) {
            std::cout << "Connack handler called" << std::endl;
            std::cout << "Session Present: " << std::boolalpha << sp << std::endl;
            std::cout << "Connack Return Code: "
                      << mqtt::connect_return_code_to_str(connack_return_code) << std::endl;
            if (connack_return_code == mqtt::connect_return_code::accepted) {
                c->subscribe("topic1", mqtt::qos::at_most_once);
            }
            return true;
        }
    );
    c->set_close_handler(
        [] {
        }
    );
    c->set_error_handler(
        []
        (boost::system::error_code const& ec) {
        }
    );
    c->set_puback_handler(
        [](std::uint16_t packet_id) {
            return true;
        }
    );
    c->set_pubrec_handler(
        [](std::uint16_t packet_id) {
            return true;
        }
    );
    c->set_pubcomp_handler(
        [](std::uint16_t packet_id) {
            return true;
        }
    );
    c->set_suback_handler(
        [&c](std::uint16_t packet_id, std::vector<boost::optional<std::uint8_t>> results) {
            std::cout << "suback received. packet_id: " << packet_id << std::endl;
            for (auto const& e : results) {
                if (e) {
                    std::cout << "subscribe success: " << mqtt::qos::to_str(*e) << std::endl;
                }
                else {
                    std::cout << "subscribe failed" << std::endl;
                }
            }
            c->publish_at_most_once("topic1", "test1");
            return true;
        }
    );
    c->set_publish_handler(
        [&c]
        (std::uint8_t header,
         boost::optional<std::uint16_t> packet_id,
         std::string topic_name,
         std::string contents) {
            std::cout << "publish received. "
                      << "dup: " << std::boolalpha << mqtt::publish::is_dup(header)
                      << " pos: " << mqtt::qos::to_str(mqtt::publish::get_qos(header))
                      << " retain: " << mqtt::publish::is_retain(header) << std::endl;
            if (packet_id)
                std::cout << "packet_id: " << *packet_id << std::endl;
            std::cout << "topic_name: " << topic_name << std::endl;
            std::cout << "contents: " << contents << std::endl;
            c->disconnect();
            return true;
        }
    );

    c->connect();

    ioc.run();
}