Клиент Eclipse Paho MQTT: как проверить существующее соединение?

На веб-сайте Eclipse Paho MQTT разработчики предоставляют пример клиента (http://www.eclipse.org/paho/files/mqttdoc/MQTTClient/html/pubsync.html), который делает следующее:

  1. Создать клиентский объект с указанными параметрами
  2. Подключить клиент с указанными параметрами подключения
  3. Публикация MQTT-сообщения
  4. Отключить клиент
  5. Уничтожить клиентский объект

Это хорошо работает, если все, что вы хотите, это опубликовать одно сообщение.

В моем коде есть функция, которая содержит почти тот же код, что и в вышеупомянутом примере, однако функция многократно вызывается из main(), так как мне нужно публиковать большое количество сообщений одно за другим. Проблема в том, что если я использую код точно так же, как в примере, каждый раз, когда вызывается моя функция, создается новое соединение, которое вскоре после этого уничтожается. Это происходит снова и снова и снова, пока функция вызывается неоднократно, вызывая огромные накладные расходы.

Есть ли способ проверить, был ли уже создан клиентский объект, и если да, то не делать этого снова, а использовать существующий?

Насколько я понимаю, это должна делать функция MQTTClient_isConnected(): noreferrer">https://www.eclipse.org/paho/files/mqttdoc/MQTTClient/html/_m_q_t_t_client_8h.html#ad9e40bdb7149ee3e5d075db7f51a735f Но если я попробую так, я получу ошибку сегментации:

if (!MQTTClient_isConnected(client)) {
    MQTTClient_create(&client, mqtt.addr, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;
    conn_opts.username = TOKEN;

    if (MQTTClient_connect(client, &conn_opts) != MQTTCLIENT_SUCCESS) {
        printf("\n==> Connection to MQTT Broker failed.\n");
        MQTTClient_destroy(&client);
        exit(EXIT_FAILURE);
    }
}

[ИЗМЕНИТЬ]

Вот простой демонстрационный код, который лучше иллюстрирует то, что я пытаюсь сделать:

#include <stdio.h>
#include <MQTTClient.h>

MQTTClient client;

void publish_MQTT() {
    MQTTClient_connectOptions conn_opts =  MQTTClient_connectOptions_initializer;
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    MQTTClient_deliveryToken token;
    char *payload = (char *)calloc(1024, sizeof(char));

    strcpy(payload, "hello");

    printf("DEBUG_BEFORE >> MQTTClient_isConnected(client) = %d\n", MQTTClient_isConnected(client)); // DEBUG OUTPUT

    if (!MQTTClient_isConnected(client)) {
        MQTTClient_create(&client, addr, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
        conn_opts.keepAliveInterval = 20;
        conn_opts.cleansession = 1;
        conn_opts.username = TOKEN;

        if (MQTTClient_connect(client, &conn_opts) != MQTTCLIENT_SUCCESS) {
            fprintf(stderr, RED "\n==> Connection to MQTT Broker failed.\n" RESET_CL);
            MQTTClient_destroy(&client);
            free(payload);
            exit(EXIT_FAILURE);
        }
    }

    printf("DEBUG_AFTER >> MQTTClient_isConnected(client) = %d\n", MQTTClient_isConnected(client)); // DEBUG OUTPUT

    pubmsg.payload = payload;
    pubmsg.payloadlen = strlen(payload);
    pubmsg.qos = QOS;
    pubmsg.retained = 0;

    MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token);
    MQTTClient_waitForCompletion(client, token, TIMEOUT);

    //MQTTClient_disconnect(client, 10000);
    //MQTTClient_destroy(&client);
    free(payload);
}

int main(void) {
    for (i=0; i<1000; i++) {
        publish_MQTT();
    }

    return 0;
}

Пожалуйста, игнорируйте тот факт, что параметр addr никогда не указывается (в моем реальном коде это так) или что довольно бесполезно указывать сообщение в функции publish_MQTT() (в моем реальном коде данные передаются из main() в эту функцию). ).


person ci7i2en4    schedule 23.05.2018    source источник


Ответы (2)


Я понял: по-видимому, в кодах примеров в исходной публикации нет абсолютно ничего плохого.

Оказывается, я снова и снова добавлял порт сервера MQTT к параметру addr (в части кода, не показанной здесь, поскольку я не подозревал, что источник ошибки находится там), каждый раз, когда publish_MQTT( ) была вызвана функция. Это привело к тому, что строка символа addr увеличилась и в конечном итоге превысила указанную длину, что привело к ошибке SegFault.

Таким образом, все работает так, как задумано:

printf("\nADDR = %s\n\n", addr); // DEBUG OUTPUT

if (!MQTTClient_isConnected(client)) {
    strcat(strcat(addr, ":"), pt); // This line needed to be placed here, not before that if block

    MQTTClient_create(&client, addr, CLIENT_ID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;
    conn_opts.username = TOKEN;

    if (MQTTClient_connect(client, &conn_opts) != MQTTCLIENT_SUCCESS) {
        printf("\n==> Connection to MQTT Broker failed.\n");
        MQTTClient_destroy(&client);
        free(payload);
        exit(EXIT_FAILURE);
    }
}
person ci7i2en4    schedule 27.05.2018

Вероятно, вы устанавливаете «флаг чистой сессии», что означает: «Если ClientId представляет Клиента, уже подключенного к Серверу, то Сервер ДОЛЖЕН отключить существующий Клиент [MQTT-3.1.4-2]». (из стандарта mqtt). Итак, ваш клиент отключен (существующий).

Код из примера кажется разумным. Похоже, есть проблема с передачей аргумента функции. Например, если функции нужен адрес, а вы сами отдаете объекты.

Морзе из стандарта: «3.2.2.2 Текущая позиция сеанса: бит 0 флагов подтверждения подключения.

Если Сервер принимает соединение с CleanSession, установленным на 1, Сервер ДОЛЖЕН установить Session Present на 0 в пакете CONNACK в дополнение к установке нулевого кода возврата в пакете CONNACK [MQTT-3.2.2-1].

Если Сервер принимает соединение с CleanSession, установленным на 0, значение, установленное в Session Present, зависит от того, сохранил ли Сервер уже состояние сеанса для предоставленного идентификатора клиента. Если Сервер сохранил состояние сеанса, он ДОЛЖЕН установить Session Present равным 1 в пакете CONNACK [MQTT-3.2.2-2]. Если сервер не имеет сохраненного состояния сеанса, он ДОЛЖЕН установить Session Present в 0 в пакете CONNACK. Это в дополнение к установке нулевого кода возврата в пакете CONNACK".

person Tomasz Pluta    schedule 25.05.2018
comment
Насколько я понимаю документацию Paho MQTT C, в функцию MQTTClient_isConnected() должен передаваться клиентский объект, а не его адрес. Или это неправильно? Кроме того, я не думаю, что conn_opts.cleansession = 1; проблема в том, что в любом случае это происходит только один раз (когда клиент изначально создается; впоследствии эта строка кода больше никогда не должна быть достигнута). Я предоставил упрощенный пример моего кода в исходном сообщении. Теперь я не понимаю двух вещей: ... - person ci7i2en4; 27.05.2018
comment
1) Если я передам клиентский объект функции MQTTClient_isConnected(), приветственное сообщение будет успешно опубликовано на сервере ровно 16 раз (до того, как произойдет ошибка сегментации), и я не верю, что это совпадение?! Есть ли где-нибудь размер массива, превышенный с 17-й попытки? 2) Если я передам &client указанной функции, сообщение на сервер не будет передано. Вместо этого я получаю ==> Ошибка подключения к MQTT Broker. Может ли кто-нибудь объяснить мне это, пожалуйста? - person ci7i2en4; 27.05.2018