簡體   English   中英

Mosquitto:使用非靜態回調 function

[英]Mosquitto: Use non-static callback function

我在我的 RPI4 上運行 Mosquitto。 但是知道我只能設置 static 回調函數。 有沒有辦法使用 class 成員?

我嘗試使用std::bind將 class 成員 function 作為回調傳遞:

主文件

#include <stdio.h>
#include <mosquitto.h>
#include "mqtt.h"
#include <string>

int main(int argc, char **argv)
{
    
    MqttConnector * mqtt = new MqttConnector("piClient", "send", "rc", 1883, "localhost", 60);
    mqtt->startClient();
    return 0;
}

mqtt.h(僅重要部分

#include <mosquitto.h>
#include <string>
#include <stdio.h>


class MqttConnector
{
    
public:
    MqttConnector(std::string id, 
                  std::string sendTopic, 
                  std::string receiveTopic, 
                  int port, 
                  std::string host,
                  int keepalive);
    ~MqttConnector();
    void startClient();

private:
    void messageCallback(struct mosquitto *mosq, 
                         void *userdata, 
                         const struct mosquitto_message *message);
    
    struct mosquitto *mosqClient = NULL;
    int keepalive;
    int port;
    std::string id;
    std::string host;
    std::string sendTopic;
    std::string receiveTopic;

};

mqtt.cpp

#include "mqtt.h"
#include <stdio.h>
#include <string>
#include <string.h>
#include <mosquitto.h>
#include <functional>

using namespace std::placeholders;

MqttConnector::MqttConnector(std::string id, std::string sendTopic, std::string receiveTopic, int port, std::string host, int keepalive)
{   
    
    mosquitto_lib_init();
    mosqClient = mosquitto_new(NULL, true, NULL);
    
    if(!mosqClient){
        fprintf(stderr, "Error: Out of memory.\n");
    }
    
    this->keepalive = keepalive;
    this->id = id;
    this->host = host;
    this->port = port;
    this->sendTopic = sendTopic;
    this->receiveTopic = receiveTopic;

}

MqttConnector::~MqttConnector()
{
    mosquitto_destroy(mosqClient);
    mosquitto_lib_cleanup();
}

void MqttConnector::messageCallback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{   
    // I want to access class members like sendTopic / receiveTopic here
}


void MqttConnector::startClient()
{
    // try to bind class members function
    mosquitto_message_callback_set(mosqClient, std::bind(&MqttConnector::messageCallback, this, _1, _2, _3));

    //other stuff
}

這在編譯時給了我以下錯誤:

cannot convert 'std::_Bind_helper<false, void (MqttConnector::*)(mosquitto*, void*, const mosquitto_message*), MqttConnector*, const std::_Placeholder<1>&, const std::_Placeholder<2>&, const std::_Placeholder<3>&>::type' {aka 'std::_Bind<void (MqttConnector::*(MqttConnector*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(mosquitto*, void*, const mosquitto_message*)>'} to 'void (*)(mosquitto*, void*, const mosquitto_message*)'
   83 |  mosquitto_message_callback_set(mosqClient, std::bind(&MqttConnector::messageCallback, this, _1, _2, _3));

為什么它不起作用?

謝謝!

這是使用 C++ 的 C-api 的問題。 會員 function 和免費 function 有什么區別? 當您提供指向成員 function 的指針時,指向 class object 的指針被隱式傳遞為第一個參數。 由於C-api不這樣做,但是問題是眾所周知的,所以引入了解決方案,它被稱為傳遞上下文。 通常它是通過一個 void 指針來完成的。 注冊回調的函數通常采用指向空閑 function 的指針和指向上下文的指針。 然后這個指針將作為回調參數之一傳遞。

在 mosquitto 情況下,此上下文指針在創建帶有 mosquitto_new 的 mosquitto object 時預先傳遞。

為了使回調 function 表現得像 C function,我們將其聲明為 ZA81229759CEF8E65D246

在回調 function 中,我們使用 static_cast 將 void 指針強制轉換為我們提供的 object。

MQTT.h

#include <mosquitto.h>
#include <string>
#include <stdio.h>


class MqttConnector
{
    
public:
    MqttConnector(std::string id, 
                  std::string sendTopic, 
                  std::string receiveTopic, 
                  int port, 
                  std::string host,
                  int keepalive);
    ~MqttConnector();
    void startClient();

private:

    // make this function static
    ---->
    static void messageCallback(struct mosquitto *mosq, 
                         void *userdata, 
                         const struct mosquitto_message *message);
    
    struct mosquitto *mosqClient = NULL;
    int keepalive;
    int port;
    std::string id;
    std::string host;
    std::string sendTopic;
    std::string receiveTopic;

};

mqtt.cpp

#include "mqtt.h"
#include <stdio.h>
#include <string>
#include <string.h>
#include <mosquitto.h>
#include <functional>

using namespace std::placeholders;

MqttConnector::MqttConnector(std::string id, std::string sendTopic, std::string receiveTopic, int port, std::string host, int keepalive)
{   
    
    mosquitto_lib_init();
    // provide apointer to this as user data
    mosqClient = mosquitto_new(NULL, true, this);
                                         ---->
    if(!mosqClient){
        fprintf(stderr, "Error: Out of memory.\n");
    }
    
    this->keepalive = keepalive;
    this->id = id;
    this->host = host;
    this->port = port;
    this->sendTopic = sendTopic;
    this->receiveTopic = receiveTopic;

}

MqttConnector::~MqttConnector()
{
    mosquitto_destroy(mosqClient);
    mosquitto_lib_cleanup();
}

void MqttConnector::messageCallback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{   
    // Use static cast to get pointer to your class object from userdata
    MqttConnector *connector = static_cast<MqttConnector>(userdata);
    connector->sendTopic;
}    

void MqttConnector::startClient()
{
    // static callback
    mosquitto_message_callback_set(mosqClient, &MqttConnector::messageCallback);

    // lambda callback
    // beware, you can't use capture here
    mosquitto_message_callback_set(&m, [/*no capture possible*/] (struct mosquitto *, void *userdata, const struct mosquitto_message *) 
{
    MqttConnector *connector = static_cast<MqttConnector>(userdata);
    connector->sendTopic;
});
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM