acl/lib_acl_cpp/samples/mqtt
2022-07-13 09:38:26 +08:00
..
mqtt_aclient test mqtt server mode 2021-03-11 19:03:22 +08:00
mqtt_aserver test mqtt server mode 2021-03-11 19:03:22 +08:00
mqtt_client test mqtt 2022-07-13 09:38:26 +08:00
mqtt_length test mqtt length's encoding 2021-03-25 16:43:02 +08:00
mqtt_pub test mqtt 2022-07-13 09:38:26 +08:00
mqtt_server test mqtt in aio/bio, client/server mode 2021-03-11 20:19:53 +08:00
Makefile test mqtt in aio/bio, client/server mode 2021-03-11 20:19:53 +08:00
README.md write mqtt readme 2021-03-28 22:34:33 +08:00

The streaming mqtt parser in acl

1. About

Because most of mqtt parsers at present are bound with network IO, which limits their using scope when we just want a mqtt parser to be used in our own network libs. I've complete a streaming mqtt in FSMFinite State Machinemode which can be used by any network libs(TCP ore UDP).

The streaming mqtt parser implemented in acl was written in standard C++, which can be used client or server sides, including all the mqtt commands such as CONNECT, CONNACK, PUBLISH, PUBACK, etc.

2. C++ API

The MQTT module in acl includes MQTT commands and MQTT network IO that each MQTT command was implemented as a C++ class. The user can set the MQTT C++ object to build for each MQTT command, and send the data after serializing the C++ object.

The MQTT commands classes include mqtt_connect, mqtt_connack, mqtt_disconnect, mqtt_publish, mqtt_puback, mqtt_pubcomp, mqtt_pubrec, mqtt_rel, mqtt_subscribe, mqtt_suback, mqtt_unsubscribe, mqtt_unsuback, mqtt_pingreq, mqtt_pingresp which are inheriting from the base class mqtt_message. The mqtt_header class in acl mqtt is used to parse or build the mqtt header.

The mqtt_client, mqtt_aclient are the network communication classes of acl mqtt, which mqtt_client uses the sync IO, and mqtt_aclient uses async IO.

3. Samples

Although the mqtt parser of acl is alone from network IO, the network IO module for mqtt was also provided, including sync IO and async IO. Some mqtt samples were written by acl mqtt are shown in mqtt_samples path.

  • mqtt_aclient: A MQTT client in async IO mode;
  • mqtt_aserver: A MQTT server in async IO mode;
  • mqtt_client: A MQTT client in sync IO mode;
  • mqtt_server: A MQTT server in sync IO mode;
  • mqtt_pub: A MQTT publish client in sync IO mode.

3.1 Write a MQTT client in sync IO mode with acl mqtt

At first, we should construct a MQTT command C++ class object as below:

        acl::mqtt_connect message;

        message.set_cid("client-id-test-xxx");
        message.set_username("user-zsx");
        message.set_passwd("pass-zsx");
        message.set_will_qos(acl::MQTT_QOS0);
        message.set_will_topic("test/topic");
        message.set_will_msg("msg-hello");

The second, construct a MQTT IO object and send the MQTT command object:

        const char* addr = "127.0.0.1|1883";
        int conn_timeout = 10 /* seconds */, rw_timeout = 0;
        acl::mqtt_client conn(addr, conn_timeout, rw_timeout);
        if (!conn.send(message)) {
                printf("send MQTT message failed!\r\n");
        } else {
                printf("send MQTT message success!\r\n");
        }

At last, waiting for the MQTT messages from MQTT server:

static bool handle_message(acl::mqtt_client& conn, acl::mqtt_message& message) {
        acl::mqtt_type_t type = message.get_header().get_type();
        switch (type) {
        case acl::MQTT_CONNACK:
                return handle_connack(conn, message);
        case acl::MQTT_PINGREQ:
                return handle_pingreq(conn);
        case acl::MQTT_PINGRESP:
                return handle_pingresp();
        case acl::MQTT_DISCONNECT:
                return handle_disconnect(message);
        case acl::MQTT_SUBACK:
                return handle_suback(conn, message);
        case acl::MQTT_PUBLISH:
                return handle_publish(conn, message);
        default:
                printf("unknown type=%d\r\n", (int) type);
                return false;
        }
}

static void waiting_messages(acl::mqtt_client& conn) {
        while (true) {
                acl::mqtt_message* res = conn.get_message();
                if (res == NULL) {
                        printf("read message error\r\n");
                        break;
                }
                if (!handle_message(conn, *res)) {
                        delete res;
                        break;
                }
                delete res;
        }
}

After getting the CONNACK we can send SUBSCRIBE command to MQTT server:

static __thread unsigned short __pkt_id = 0;

static bool handle_connack(acl::mqtt_client& conn, const acl::mqtt_message& message) {
        const acl::mqtt_connack& connack = (const acl::mqtt_connack&) message;

        printf("%s => connect code=%d\r\n", __FUNCTION__, connack.get_connack_code());

        // constrcut SUBSCRIBE command and send it to the MQTT server

        acl::mqtt_subscribe sub;

        if (++__pkt_id == 0) {
                __pkt_id = 1;  // the pkt id must more than zero.
        }
        sub.set_pkt_id(__pkt_id);

        sub.add_topic("test/topic1", acl::MQTT_QOS1);
        sub.add_topic("test/topic2", acl::MQTT_QOS1);
        sub.add_topic("test/topic3", acl::MQTT_QOS1);

        if (conn.send(sub)) {
                printf("send subscribe ok\r\n");
                return true;
        }

        printf("send subscribe error\r\n");
        return false;
}

We can easily complete The left functions in handle_message() above including handle_pingreq, handle_pingresp, handle_disconnect, handle_suback, handle_publish.

3.2 Write a MQTT server in sync IO mode with acl mqtt

3.3 Write a MQTT client in async IO mode with acl mqtt

3.4 Write a MQTT server in async IO mode with acl mqtt

4. Compile acl mqtt module

Because acl mqtt lib is a part of lib_acl_cpp lib, and lib_acl_cpp depend lib_acl and lib_protocol, you should compile lib_acl and lib_protocol libs first, and compile lib_acl_cpp lib. After you've compiled lib_acl_cpp lib, the module lib is also compiled OK.

4.1 Compile on UNIX/LINUX

  • 1 compile lib_acl.a: Enter into lib_acl path and type make, the lib_acl.a will be compiled
  • 2 compile lib_protocol.a: Enter into lib_protocol path and type make, the lib_protocol.a will be compiled
  • 3 compile lib_acl_cpp.a: Enter into lib_acl_cpp path and type make, the lib_acl_cpp.a will be compiled
  • 4 compile mqtt samples: Enter into lib_acl_cpp\samples\mqtt and type make, all the mqtt samples will be compiled.

4.2 Compile on WINDOWS

You can use VC2003, VC2008, VC2010, VC2012, VC2015, VC2017, VC2019 to build all acl libs including acl mqtt module in lib_acl_cpp module when you open the acl projects(acl_cpp_vc2003.sln, acl_cpp_vc2008.sln, acl_cpp_vc2010.sln, acl_cpp_vc2012.sln, acl_cpp_vc2015.sln, acl_cpp_vc2017.sln, acl_cpp_vc2019.sln). You should build lib_acl first, and second build lib_protocol, and third build lib_acl_cpp, and at last build all the acl samples including mqtt samples.

5. Reference

The source files are in mqtt src files, and the header files are in mqtt header files.