C++ MQTT通讯实例示例
本文从以下几个方面进行说明:
- MQTT C++ Client Library 安装
- Linux C++ 发布端代码
- Linux C++ 订阅端代码
关于MQTT开发环境的搭建,详见:
https://blog.youkuaiyun.com/limeigui/article/details/125676842?spm=1001.2014.3001.5502
1. MQTT C++ Client Library 安装
参考: https://github.com/eclipse/paho.mqtt.cpp
1.1. install doxygen
Building the documentation requires doxygen and optionally graphviz to be installed:
$ sudo apt-get install doxygen graphviz
1.2. Building the Paho C library
Before building the C++ library, first, build and install the Paho C library, if not already present. Note, this version of the C++ library requires Paho C v1.3.8 or greater.
$ git clone https://github.com/eclipse/paho.mqtt.c.git
$ cd paho.mqtt.c
$ git checkout v1.3.8
$ cmake -Bbuild -H. -DPAHO_ENABLE_TESTING=OFF -DPAHO_BUILD_STATIC=ON \
-DPAHO_WITH_SSL=ON -DPAHO_HIGH_PERFORMANCE=ON
$ sudo cmake --build build/ --target install
$ sudo ldconfig
1.3. Building the Paho C++ library
$ git clone https://github.com/eclipse/paho.mqtt.cpp
$ cd paho.mqtt.cpp
$ cmake -Bbuild -H. -DPAHO_BUILD_STATIC=ON \
-DPAHO_BUILD_DOCUMENTATION=TRUE -DPAHO_BUILD_SAMPLES=TRUE
$ sudo cmake --build build/ --target install
$ sudo ldconfig
2. Linux C++ 发布端代码
#include <iostream>
#include <sstream>
#include "mqtt/async_client.h"
#include "mqtt/properties.h"
#include <chrono>
const string SERVER_ADDRESS { "tcp://127.0.0.1:1883" }; //tcp://172.17.0.1:1883
const auto TIMEOUT = std::chrono::seconds(10);
int main(int argc, char* argv[])
{
if (argc < 2) {
cout << "USAGE: rpc_math_cli <add|query|delete>" << endl;
return 1;
}
constexpr int QOS = 1;
const string REQ_TOPIC_HDR { "/mqttTopicName" };
const string client_id = "zzzyc";
mqtt::create_options createOpts(MQTTVERSION_5);
mqtt::async_client cli(SERVER_ADDRESS, client_id, createOpts);
auto connOpts = mqtt::connect_options_builder()
.user_name("waytous")
.password("1")
.mqtt_version(MQTTVERSION_5)
.clean_start()
.finalize();
cli.start_consuming();
try {
cout << "Connecting..." << flush;
mqtt::token_ptr tok = cli.connect(connOpts);
auto connRsp = tok->get_connect_response();
cout << "OK (" << connRsp.get_server_uri() << ")" << endl;
string repTopic = "replies/" + client_id + "/mqttTopicName";
cout << " Reply topic: " << repTopic << endl;
// Subscribe to the reply topic and verify the QoS
tok = cli.subscribe(repTopic, QOS);
tok->wait();
if (int(tok->get_reason_code()) != QOS) {
cerr << "Error: Server doesn't support reply QoS: ["
<< tok->get_reason_code() << "]" << endl;
return 2;
}
// Create and send the request message
string req { argv[1] },
reqTopic { REQ_TOPIC_HDR + req };
mqtt::properties props {
{ mqtt::property::RESPONSE_TOPIC, repTopic },
{ mqtt::property::CORRELATION_DATA, "1" }
};
string s = "MQTT Request Msg";
string reqArgs { s};
cout << "publish topic name: " << reqTopic << endl;
cout << "\nSending request data: " << reqArgs << "..." << flush;
auto pubmsg = mqtt::message_ptr_builder()
.topic(reqTopic)
.payload(reqArgs)
.qos(QOS)
.properties(props)
.finalize();
cli.publish(pubmsg)->wait_for(TIMEOUT);
cout << "OK" << endl;
// Wait for reply.
auto temp = updateDynamicHdmapLayer();
if(s == temp)
{
cout <<"success" << endl;
}
else
{
cout <<" failed"<<endl;
cout << s << endl;
cout << temp << endl;
}
auto msg = cli.try_consume_message_for(seconds(5));
if (!msg) {
cerr << "Didn't receive a reply from the service." << endl;
return 1;
}
cout << " Result: " << msg->to_string() << endl;
// Unsubscribe
cli.unsubscribe(repTopic)->wait();
// Disconnect
cout << "\nDisconnecting..." << flush;
cli.disconnect()->wait();
cout << "OK" << endl;
}
catch (const mqtt::exception& exc)
{
cerr << exc.what() << endl;
return 1;
}
return 0;
}
3. Linux C++ 订阅端代码
#include <iostream>
#include <sstream>
#include "mqtt/client.h"
const std::string SERVER_ADDRESS { "tcp://127.0.0.1:1883" }; //todo: tcp://localhost:1883
const std::string CLIENT_ID { "rpc_math_srvr" };
constexpr auto RESPONSE_TOPIC = mqtt::property::RESPONSE_TOPIC;
constexpr auto CORRELATION_DATA = mqtt::property::CORRELATION_DATA;
bool try_reconnect(mqtt::client& cli)
{
constexpr int N_ATTEMPT = 30;
for (int i=0; i<N_ATTEMPT && !cli.is_connected(); ++i)
{
try
{
cli.reconnect();
return true;
}
catch (const mqtt::exception&)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
return false;
}
int main(int argc, char* argv[])
{
mqtt::create_options createOpts(MQTTVERSION_5);
mqtt::client cli(SERVER_ADDRESS, client_id, createOpts);
auto connOpts = mqtt::connect_options_builder()
.mqtt_version(MQTTVERSION_5)
.user_name("zyc")
.password("1")
.keep_alive_interval(std::chrono::seconds(20))
.clean_start(true)
.finalize();
std::string topicNameOfMqttMsg = "/mqttTopicName";
const std::vector<std::string> TOPICS { topicNameOfMqttMsg, topicNameOfMqttMsg + "/#" };
const std::vector<int> QOS { 1, 1 };
try
{
std::cout << str_busi_name << " : Connecting to the MQTT server(ReceiveMsg)... " << std::endl;
do
{
try
{
auto result = cli.connect(connOpts);
if (!cli.is_connected())
{
usleep(1000);
std::cout << str_busi_name <<": re cli.connect()" << std::endl;
continue;
}
break;
}
catch (const mqtt::exception& exc)
{
std::cerr << "[" << __LINE__ << "]" << str_busi_name << " : " << exc.what() << std::endl;
usleep(1000); //tdo:
continue;
}
}while(true);
cli.subscribe(TOPICS, QOS);
std::cout << str_busi_name <<" : OK \n" << std::endl;
// Consume messages
std::cout << str_busi_name <<" : Waiting for RPC requests..." << std::endl;
while (true)
{
auto msg = cli.consume_message();
if (!msg)
{
if (!cli.is_connected())
{
std::cout << str_busi_name <<" : Lost connection. Attempting reconnect" << std::endl;
if (try_reconnect(cli))
{
cli.subscribe(TOPICS, QOS);
std::cout << str_busi_name <<" : Reconnected" << std::endl;
continue;
}
else
{
std::cout << str_busi_name <<" : Reconnect failed." << std::endl;
break;
}
}
else
break;
}
std::cout << str_busi_name <<" : Received a request" << std::endl;
const mqtt::properties& props = msg->get_properties();
if(!props.contains(RESPONSE_TOPIC) || !props.contains(CORRELATION_DATA))
{
logger_main->error("[{0}][{1}][{2}] Error Request Msg: ", __CLASS__, __FUNCTION__ ,__LINE__);
continue;
}
mqtt::binary corr_id = mqtt::get<std::string>(props, CORRELATION_DATA);
std::string reply_to = mqtt::get<std::string>(props, RESPONSE_TOPIC);
std::cout << str_busi_name <<" : Client wants a reply to [" << corr_id << "] on '" << reply_to << "'" << std::endl;
//std::cout << msg->get_topic() << ": " << msg->to_string() << std::endl;
std::string str_response = "MQTT Reponse Msg. ";
auto reply_msg = mqtt::message::create(reply_to, pqxx::to_string(str_response), 1, false);
cli.publish(reply_msg);
usleep(100); //tdo:
}
// Disconnect
std::cout << str_busi_name <<" : Disconnecting from the MQTT server..." << std::endl;
cli.disconnect();
std::cout << str_busi_name <<" : OK" << std::endl;
}
catch (const mqtt::exception& exc)
{
//std::cerr << exc.what() << std::endl;
std::cerr << "[" << __LINE__ << "]" << str_busi_name << " : " << exc.what() << std::endl;
return 1;
}
return 0;
}