我正在尝试为一个名为 libumqtt 的库实现一个包装器。Libumqtt是一个 C 库,它使用 libev 对来自 MQTT 协议的事件进行回调。
直到前几天我才意识到我无法将成员函数传递给需要正常静态函数的函数。这会导致问题,因为我计划启动多个 libumqtt 实例以同时处理多个连接。
我的代码在 C++ 中,因为这是与 Godot 的(游戏引擎)GDNative 模块一起使用最方便的。
在研究一种将 ac 库的多个实例沙箱化或以某种方式使指针正常工作的方法时,我找到了这个答案。我不明白答案中的这句话:
如果您需要访问类的任何非静态成员并且需要使用函数指针,例如,因为该函数是 C 接口的一部分,那么您最好的选择是始终将 void* 传递给采用函数指针的函数并通过转发函数调用您的成员,该函数从 void* 获取对象,然后调用成员函数。
我想要做的是设置回调,当它同时处理可能多达 500 个或更多连接时,libev 将使用该回调将数据发送到我的对象的正确实例。
通过 void* 会帮助我实现我的目标吗?我将如何实现它?另外,转发功能如何工作?
编辑:提供核桃要求的代码示例
下面的这个例子来自我使用静态函数的类的一个版本。如果我尝试在函数不是静态的情况下使用 run this,那么我会收到一个错误,即无法传入成员函数来代替常规函数。
// Client.cpp
void Client::signal_cb(struct ev_loop *loop, ev_signal *w, int revents) {
ev_break(loop, EVBREAK_ALL);
}
// ...
void Client::do_connect(struct ev_loop *loop, struct ev_timer *w, int revents) {
//Godot::print("Attempt MQTT Start!!!\n");
//write_log("debug", "MQTT Wrapper - Attempt MQTT Start!!!");
struct umqtt_client *cl; // Move to Class Access (Private)?
cl = umqtt_new(loop, cfg.host, cfg.port, cfg.ssl);
if (!cl) {
//Godot::print("Failed To Create Client!!!\n");
//write_log("debug", "MQTT Wrapper - Failed To Create Client!!!");
start_reconnect(loop);
return;
}
//Godot::print("Setup Client Callbacks!!!\n");
//write_log("debug", "MQTT Wrapper - Setup Client Callbacks!!!");
// For StackOverflow: These cl->... lines do not work because of not being able to pass a member function as a regular function. These are the main callbacks I have trouble with.
// How do I convert from `void (libumqtt::Client::*)(struct umqtt_client *)` to `void (*)(struct umqtt_client *)`?
cl->on_net_connected = Client::on_net_connected; // Pass member function as a non-static object
cl->on_conack = Client::on_conack; // Pass member function as a non-static object
cl->on_suback = Client::on_suback; // Pass member function as a non-static object
cl->on_unsuback = Client::on_unsuback; // Pass member function as a non-static object
cl->on_publish = Client::on_publish; // Pass member function as a non-static object
cl->on_pingresp = Client::on_pingresp; // Pass member function as a non-static object
cl->on_error = Client::on_error; // Pass member function as a non-static object
cl->on_close = Client::on_close; // Pass member function as a non-static object
//Godot::print("MQTT Start!!!\n");
//write_log("debug", "MQTT Wrapper - MQTT Start!!!");
}
void Client::initialize() {
// For StackOverflow: These two lines cannot work in an object as libev expects signal_cb and do_connect to be regular functions. These callbacks are also necessary, but I am not sure how to handle this.
ev_signal_init(&signal_watcher, Client::signal_cb, SIGINT);
ev_timer_init(&reconnect_timer, Client::do_connect, 0.1, 0.0); // Fix Me - Make ev.h object
// ...
}
编辑:我应该提到我是使用 C 和 C++ 的菜鸟。我之前做的最多的是测试缓冲区溢出。因此,如果我显然做错了什么,我将不胜感激评论中的提示。