Eclipse Paho MQTT Client:如何检查现有连接?

时间:2018-05-23 14:23:17

标签: c mqtt paho

在Eclipse Paho MQTT网站上,开发人员提供了一个客户端示例(http://www.eclipse.org/paho/files/mqttdoc/MQTTClient/html/pubsync.html),它执行以下操作:

  1. 使用指定参数创建客户端对象
  2. 使用指定的连接选项
  3. 连接客户端
  4. 发布MQTT消息
  5. 断开客户端
  6. 销毁客户端对象
  7. 如果你想要的只是发布一条消息,这很有效。

    在我的代码中,我有一个函数包含与上述示例中几乎相同的代码,但是,从main()重复调用该函数,因为我需要一个接一个地发布大量消息。问题是,如果我使用与示例中完全相同的代码,每次调用我的函数时,都会创建一个新连接,并在销毁后不久。只要重复调用该函数,就会一次又一次地发生这种情况,从而导致巨大的开销。

    有没有办法检查是否已经创建了一个客户端对象,如果是,那么不要再次使用现有的对象?

    根据我的理解,MQTTClient_isConnected()函数应该这样做: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()传递的该功能)。

2 个答案:

答案 0 :(得分:1)

我明白了:显然,原始帖子中的示例代码完全没有问题。

事实证明我是一次又一次地将MQTT服务器的端口附加到addr参数(在此处未显示的代码部分,因为我没有怀疑错误的来源在那里),每次调用了publish_MQTT()函数。这使得addr char字符串增长并最终超过指定的长度,从而导致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);
    }
}

答案 1 :(得分:0)

可能你正在设置“清洁会议标志”,这是什么意思:“    如果ClientId表示已连接到服务器的客户端,那么服务器必须断开现有客户端[MQTT-3.1.4-2]。“(来自mqtt标准)。所以客户端断开连接(现有客户端)。

示例中的代码似乎是可重用的。看起来传递函数参数有问题。例如,如果函数需要地址,并且您自己提供对象。

标准化: “3.2.2.2会议现场 位置:Connect Acknowledge Flags的第0位。

如果服务器接受CleanSession设置为1的连接,除了在CONNACK数据包[MQTT-3.2.2-1]中设置零返回码之外,服务器必须在CONNACK数据包中将Session Present设置为0。 / p>

如果服务器接受将CleanSession设置为0的连接,则Session Present中设置的值取决于Server是否已为所提供的客户端ID存储了Session状态。如果服务器已存储会话状态,则它必须在CONNACK数据包[MQTT-3.2.2-2]中将Session Present设置为1。如果服务器没有存储的会话状态,它必须在CONNACK数据包中将Session Present设置为0。这是在CONNACK数据包“。

中设置零返回码的补充