Проблема с подключением MQTT PubSubClient к ESP32

У меня возникли некоторые проблемы со строкой в приложении Arduino с ESP32. Я не понимаю, почему этот код работает:

mqtt.setServer("m20.cloudmqtt.com", порт); //в порядке

а это не работает не подключается

String strSBM = "m20.cloudmqtt.com"; mqtt.setServer(strSBM.c_str(), порт); //нет ОК

Я использую библиотеку PubSubClient 2.7

Любой из вас может мне помочь

Большое спасибо

, 👍0


1 ответ


1

Когда вы устанавливаете сервер из строки C, он не копирует строку, а просто сохраняет указатель на нее:

PubSubClient& PubSubClient::setServer(const char * domain, uint16_t port) {
    this->domain = domain;
    this->port = port;
    return *this;
}

Если строка, на которую он указывает, выходит за пределы области видимости (это локальная переменная и функция завершает работу), данные строки будут признаны недействительными и потеряны.

Он действительно предназначен для работы со строковыми литералами и глобальными постоянными переменными, которые никогда не изменяются.

Если это единственный раз, когда вы когда-либо устанавливали сервер, вы можете обойтись без использования strdup() для дублирования строковых данных в куче, но без прямого доступа к domain класса PubSubClient, у вас нет возможности снова free() память, если вы когда-нибудь захотите сменить сервер.

String strSBM = "m20.cloudmqtt.com";
mqtt.setServer (strdup(strSBM.c_str()), port); 

Чтобы сделать так, чтобы вы могли освободить значение, вам нужно отслеживать его отдельно:

static char *temp = NULL;
if (temp != NULL) {
    free(temp);
    temp = NULL;
}
temp = strdup(strSBM.c_str());
mqtt.setServer(temp, port);
,

та же проблема с номером порта какую функцию я должен использовать для порта? Спасибо за вашу помощь, @Michele

Нет, не та же проблема с номером порта - это просто номер, и он копируется. Проблема существует только для имени сервера, потому что это указатель., @Majenko

Хорошо, теперь все работает с client.setServer(strdup(strSBM.c_str()), (int)strPSBM.toInt());, @Michele

Пока вы делаете это только один раз, все в порядке - если вы сделаете это более одного раза, вы создадите утечку памяти, и через некоторое время вы выйдете из строя. Почему именно вы хотите, чтобы имя сервера было в строке?, @Majenko

Ооо, тогда это не хорошо для меня, потому что в моем проекте я сохраняю имя сервера и номер порта во внешнюю EEPROM и у меня есть возможность изменить параметры конфигурации. Так что иметь статические параметры нехорошо. У Вас есть какие-то предложения?, @Michele

Создайте глобальный массив char для хранения данных. Считайте его из EEPROM в этот массив char, а затем передайте его в setServer как есть. Каждый раз, когда вы изменяете содержимое этого массива символов, библиотека PubSubClient мгновенно увидит новые данные — все, что осталось, — это снова подключиться., @Majenko

Хорошая идея, но мой проект слишком сложен для этого изменения. Что вы думаете об этой аренде символ * темп; бесплатно (темп); temp = strdup(strSBM.c_str()); client.setServer (временный, 15534); так что каждый раз я меняю параметры пустого сервера с помощью free() ??? идея помогите помогите помогите, @Michele

Конечно, это могло бы сработать, пока temp является глобальным или статическим, поэтому он остается все время. статический символ *temp = NULL; если (temp!= NULL) { бесплатно(temp); темп = НУЛЬ; } temp = strdup(strSBM.c_str()); - Важно убедиться, что для temp действительно что-то выделено, прежде чем пытаться его освободить..., @Majenko