Closed xunshichentuo closed 1 year ago
Please consider using the v2 version of this sdk: https://github.com/aws/aws-iot-device-sdk-cpp-v2
Thank you very much for your answer.
I imitated PubSub and rewritten it into qt code.
The device uses clientId to connect to the cloud. If there are duplicate IDs, the cloud will continuously disconnect my device, but the device will automatically reconnect. In this case, the device may crash after running continuously for 2 days. The topic name of MQTT is set based on this client ID.
procureStateTopicName = QString("%1/%2/%3/state").arg(envName, app_key, this->procureId);
completedQueueTopicName = QString("%1/%2/%3/state/printjob/").arg(envName, app_key, this->procureId);
deviceInfoTopicName = QString("%1/%2/%3/%4/%5").arg(envName,app_key,serialNumber,"telemetry","version");
telemetryLogTopicName = QString("%1/%2/%3/control/log-file/+").arg(envName).arg(app_key).arg(serialNumber);
newQueueJobTopicName = QString("%1/%2/%3/enqueue/printjob/+").arg(envName).arg(app_key).arg(this->procureId);
expireQueueJobTopicName = QString("%1/%2/%3/expire/printjob/+").arg(envName).arg(app_key).arg(this->procureId);
I also tried compiling the v2 version, but I couldn't find cross-compiled documents, so I gave up in the end.
cat iot_config_prod.json
{
"endpoint": "xxxxxxxxxx.iot.us-west-2.amazonaws.com",
"mqtt_port": xxxx,
"https_port": xxxx,
"greengrass_discovery_port": xxxx,
"root_ca_relative_path": "certs_iot_prod/rootCA.crt",
"device_certificate_relative_path": "certs_iot_prod/cert.pem",
"device_private_key_relative_path": "certs_iot_prod/privkey.pem",
"tls_handshake_timeout_msecs": 60000,
"tls_read_timeout_msecs": 2000,
"tls_write_timeout_msecs": 2000,
"aws_region": "us-west-2",
"aws_access_key_id": "",
"aws_secret_access_key": "",
"aws_session_token": "",
"client_id": "pro-PC2A0021500000-prod",
"thing_name": "pro-PC2A0021500000-prod",
"is_clean_session": true,
"mqtt_command_timeout_msecs": 20000,
"keepalive_interval_secs": 10,
"minimum_reconnect_interval_secs": 1,
"maximum_reconnect_interval_secs": 128,
"maximum_acks_to_wait_for": 32,
"action_processing_rate_hz": 5,
"maximum_outgoing_action_queue_length": 32,
"discover_action_timeout_msecs": 300000,
"version": "2020-06-16"
}
This is my mqttclient.h
#ifndef MQTTCLIENT_H
#define MQTTCLIENT_H
#include <QObject>
#include <QTimer>
#include <QtMath>
#include "configcommon.h"
#include "network/OpenSSL/OpenSSLConnection.hpp"
#include "include/ClientCoreState.hpp"
#include "include/mqtt/Client.hpp"
class MqttClient : public QObject
{
Q_OBJECT
public:
explicit MqttClient(QObject *parent = nullptr);
void init();
awsiotsdk::ResponseCode publish(awsiotsdk::util::String topicNameStr, awsiotsdk::util::String message);
awsiotsdk::ResponseCode subscribe(awsiotsdk::util::String topicNameStr);
awsiotsdk::ResponseCode unsubscribeTo(awsiotsdk::util::String topicNameStr);
protected:
void initializeMqttClient();
void initializeConnection();
std::shared_ptr<awsiotsdk::NetworkConnection> configNetworkConnectionInOpenSSL();
int getReconnectionIntervalMillis(int retryCount);
awsiotsdk::ResponseCode onDisconnected();
awsiotsdk::ResponseCode onReconnected();
awsiotsdk::ResponseCode onResubscribe();
awsiotsdk::ResponseCode onSubMessage(awsiotsdk::util::String topic_name,
awsiotsdk::util::String payload,
std::shared_ptr<awsiotsdk::mqtt::SubscriptionHandlerContextData> p_app_handler_data);
signals:
void reconnecting();
void updateServerStatusLater();
void mqttMessageReceived(const QString topicName, const QString message);
private:
ConfigCommon configCommon;
std::shared_ptr<awsiotsdk::NetworkConnection> networkConnection;
std::shared_ptr<awsiotsdk::MqttClient> iotClient;
int reconnectionCount = 0;
const int MAX_INIT_CONNECT_RETRY_INTERVAL_MILLIS = 60000;
const int MIN_INIT_CONNECT_RETRY_INTERVAL_MILLIS = 3000;
};
#endif // MQTTCLIENT_H
This is my mqttclient.cpp
#include "mqttclient.h"
#include "Controller/EnvironmentController/environmentcontroller.h"
MqttClient::MqttClient(QObject *parent) : QObject(parent)
{
}
void MqttClient::init()
{
initializeMqttClient();
initializeConnection();
}
awsiotsdk::ResponseCode MqttClient::publish(awsiotsdk::util::String topicNameStr, awsiotsdk::util::String message)
{
if(iotClient.get() == nullptr) {
return awsiotsdk::ResponseCode::FAILURE;
}
std::unique_ptr<awsiotsdk::Utf8String> topicName = awsiotsdk::Utf8String::Create(topicNameStr);
uint16_t packetId = 0;
qDebug() << "MqttClient::publish: " << QString::fromStdString(topicNameStr) << " - " << QString::fromStdString(message);
awsiotsdk::ResponseCode responseCode = iotClient->PublishAsync(std::move(topicName),
false, false, awsiotsdk::mqtt::QoS::QOS0,
message, nullptr, packetId);
return responseCode;
}
awsiotsdk::ResponseCode MqttClient::subscribe(awsiotsdk::util::String topicNameStr)
{
qDebug()<<"MqttClient::subscribe topicName:"<<QString::fromStdString(topicNameStr);
std::unique_ptr<awsiotsdk::Utf8String> topicName = awsiotsdk::Utf8String::Create(topicNameStr);
awsiotsdk::mqtt::Subscription::ApplicationCallbackHandlerPtr subCallbackHandler = std::bind(&MqttClient::onSubMessage,
this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3);
std::shared_ptr<awsiotsdk::mqtt::Subscription> subscription =
awsiotsdk::mqtt::Subscription::Create(std::move(topicName), awsiotsdk::mqtt::QoS::QOS1, subCallbackHandler, nullptr);
awsiotsdk::util::Vector<std::shared_ptr<awsiotsdk::mqtt::Subscription>> subscriptionList;
subscriptionList.push_back(subscription);
awsiotsdk::ResponseCode responseCode = iotClient->Subscribe(subscriptionList, configCommon.mqtt_command_timeout_);
if (responseCode != awsiotsdk::ResponseCode::SUCCESS) {
qDebug() << "Subscribe failed.";
}
/*
* Sleep to wait for the subscribe to finish
* It may not be the best way to handle async request, but it's recommended by AWSIoTSDK
* This function should be run on a separate worker thread instead of the main thread
*/
std::this_thread::sleep_for(std::chrono::seconds(3));
return responseCode;
}
awsiotsdk::ResponseCode MqttClient::unsubscribeTo(awsiotsdk::util::String topicNameStr)
{
std::unique_ptr<awsiotsdk::Utf8String> topicName = awsiotsdk::Utf8String::Create(topicNameStr);
awsiotsdk::util::Vector<std::unique_ptr<awsiotsdk::Utf8String>> unsubscribeList;
unsubscribeList.push_back(std::move(topicName));
awsiotsdk::ResponseCode responseCode = iotClient->Unsubscribe(std::move(unsubscribeList), configCommon.mqtt_command_timeout_);
std::this_thread::sleep_for(std::chrono::seconds(1));
return responseCode;
}
void MqttClient::initializeMqttClient()
{
awsiotsdk::ClientCoreState::ApplicationDisconnectCallbackPtr disconnectHandler = std::bind(&MqttClient::onDisconnected, this);
awsiotsdk::ClientCoreState::ApplicationReconnectCallbackPtr reconnectHandler = std::bind(&MqttClient::onReconnected, this);
awsiotsdk::ClientCoreState::ApplicationResubscribeCallbackPtr resubscribeHandler = std::bind(&MqttClient::onResubscribe, this);
QString configFileName = EnvironmentController::getSingleton()->getIotConfigFileName();
awsiotsdk::ResponseCode responseCode = configCommon.initializeCommon(configFileName);
if (responseCode != awsiotsdk::ResponseCode::SUCCESS) {
qDebug() << "MqttClient::initializeMqttClient - Failed to read " << configFileName << " ; ResponseCode=" << int(responseCode);
}
networkConnection = configNetworkConnectionInOpenSSL();
iotClient = std::shared_ptr<awsiotsdk::MqttClient>(
awsiotsdk::MqttClient::Create(networkConnection,
configCommon.mqtt_command_timeout_,
disconnectHandler, nullptr,
reconnectHandler, nullptr,
resubscribeHandler, nullptr));
}
void MqttClient::initializeConnection()
{
awsiotsdk::util::String clientIdStr = configCommon.base_client_id_;
std::unique_ptr<awsiotsdk::Utf8String> clientId = awsiotsdk::Utf8String::Create(clientIdStr);
awsiotsdk::ResponseCode responseCode = iotClient->Connect(configCommon.mqtt_command_timeout_,
configCommon.is_clean_session_,
awsiotsdk::mqtt::Version::MQTT_3_1_1,
configCommon.keep_alive_timeout_secs_,
std::move(clientId), nullptr, nullptr, nullptr);
if(responseCode != awsiotsdk::ResponseCode::MQTT_CONNACK_CONNECTION_ACCEPTED) {
qDebug()<<"MqttClient::initializeConnection != awsiotsdk::ResponseCode::MQTT_CONNACK_CONNECTION_ACCEPTED:"<<int(responseCode);
QTimer::singleShot(getReconnectionIntervalMillis(reconnectionCount), this, [&](){ initializeConnection(); });
reconnectionCount++;
} else {
qDebug()<<"MqttClient::initializeIotClient iotClient->Connect awsiotsdk::ResponseCode::MQTT_CONNACK_CONNECTION_ACCEPTED";
reconnectionCount = 0;
}
}
int MqttClient::getReconnectionIntervalMillis(int retryCount)
{
if(retryCount > 30) {
return MAX_INIT_CONNECT_RETRY_INTERVAL_MILLIS;
}
int interval = static_cast<int>(qPow(2, retryCount) *1000 + MIN_INIT_CONNECT_RETRY_INTERVAL_MILLIS);
interval = qMin(MAX_INIT_CONNECT_RETRY_INTERVAL_MILLIS, interval);
qDebug()<<"MqttClient::getReconnectionIntervalMillis retry in "<<interval<<"ms";
return interval;
}
awsiotsdk::ResponseCode MqttClient::onDisconnected()
{
qDebug()<<"MqttClient::onDisconnected - Ops, IoT Disconnected...";
return awsiotsdk::ResponseCode::FAILURE;
}
awsiotsdk::ResponseCode MqttClient::onReconnected()
{
qDebug()<<"MqttClient::onDisconnected - IoT Reconnected...";
emit reconnecting();
return awsiotsdk::ResponseCode::SUCCESS;
}
awsiotsdk::ResponseCode MqttClient::onResubscribe()
{
qDebug()<<"MqttClient::onResubscribe - MQTT Topics Subscribed Again!";
emit updateServerStatusLater();
return awsiotsdk::ResponseCode::SUCCESS;
}
awsiotsdk::ResponseCode MqttClient::onSubMessage(awsiotsdk::util::String topic_name, awsiotsdk::util::String payload, std::shared_ptr<awsiotsdk::mqtt::SubscriptionHandlerContextData> p_app_handler_data)
{
Q_UNUSED(p_app_handler_data)
qDebug() << "MqttClient::onSubMessage --- NEW SUB MESSAGE ---";
qDebug() << "MqttClient::onSubMessage - Received message";
qDebug() << "MqttClient::onSubMessage - Topic: " << QString::fromStdString(topic_name);
qDebug() << "MqttClient::onSubMessage - Message Length: " << payload.length();
qDebug() << "MqttClient::onSubMessage --- END OF NEW MESSAGE ---";
emit mqttMessageReceived(QString::fromStdString(topic_name), QString::fromStdString(payload));
return awsiotsdk::ResponseCode::SUCCESS;
}
std::shared_ptr<awsiotsdk::NetworkConnection> MqttClient::configNetworkConnectionInOpenSSL()
{
std::shared_ptr<awsiotsdk::network::OpenSSLConnection> networkConnectionOpenSSL =
std::make_shared<awsiotsdk::network::OpenSSLConnection>(configCommon.endpoint_,
configCommon.endpoint_mqtt_port_,
configCommon.root_ca_path_,
configCommon.client_cert_path_,
configCommon.client_key_path_,
configCommon.tls_handshake_timeout_,
configCommon.tls_read_timeout_,
configCommon.tls_write_timeout_, true);
awsiotsdk::ResponseCode responseCode = networkConnectionOpenSSL->Initialize();
if (responseCode != awsiotsdk::ResponseCode::SUCCESS) {
qDebug() << "MqttClient::configNetworkConnectionInOpenSSL() - Failed to initialize network connection in OpenSSL";
}
return std::dynamic_pointer_cast<awsiotsdk::NetworkConnection>(networkConnectionOpenSSL);
}
Can you try adding a random string to your client ID? The sample does it like this:
client_id_tagged.append(std::to_string(rand()));
As you noticed using the same client ID is causing a disconnect loop. Each client is supposed to have its own unique id
Because of the unique ID, it will not be reconnected and the probability of crashing is relatively low. Is there an API that can disable AWS IOT reconnection in devices? Thanks
You shouldn't be trying to handle you reconnecting yourself. That is part of the sdk and when you try reconnecting with same client id that can cause unexpected behavior (ie. crashes after 2 days). In the sample I previously linked you can see that connect is only ever called once vs multiple times that you are trying.
rc = p_iot_client_->Connect(ConfigCommon::mqtt_command_timeout_, ConfigCommon::is_clean_session_,
mqtt::Version::MQTT_3_1_1, ConfigCommon::keep_alive_timeout_secs_,
std::move(client_id), nullptr, nullptr, nullptr);
Please remove your retry logic and see if that fixes the crashes that you are seeing
Thank you very much. I think it's more important to avoid duplicate IDs. I have been testing for a week and there is no such problem under normal circumstances
Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.
Describe the bug
We connect through the device serial number, AWS IoT. When the device serial number is duplicated, the IoT connection will continue to be disconnected and reconnected, sometimes lasting for about 2 days and crashing.
Expected Behavior
It shouldn't have collapsed
Current Behavior
Although he may not collapse 100%, there is a probability. After a long period of operation
Reproduction Steps
Use the subAndPub example in the sample and write it in qt. Then run and use it, as the serial number is the same, it will continuously disconnect and reconnect
Possible Solution
No response
Additional Information/Context
This is gdb's crash stack record:
SDK version used
latest
Environment details (OS name and version, etc.)
ubuntu1804 imx6ull