将libuv与函数结构一起使用,而不是函数回调
Using libuv with functor structure instead of function callback
有人知道为什么在使用函子结构而不是实际函数作为回调时使用libuv-segfault吗。在下面的示例中,我创建了要使用的结构CB,而不是connection_CB。segfault发生在运算符()中。
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>
uv_buf_t alloc_buffer(uv_handle_t * handle, size_t size);
void connection_cb(uv_stream_t * server, int status);
void read_cb(uv_stream_t * stream, ssize_t nread, uv_buf_t buf);
struct CB {
State *state_;
CB(State *state) : state_(state) {}
void operator()(uv_stream_t *server, int status) {
uv_tcp_t * client = (uv_tcp_t *)malloc(sizeof(uv_tcp_t));
/* if status not zero there was an error */
if (status == -1) {
printf("error 2n");
}
/* initialize the new client */
uv_tcp_init(loop, client);
/* now let bind the client to the server to be used for incomings */
if (uv_accept(server, (uv_stream_t *) client) == 0) {
/* start reading from stream */
int r = uv_read_start((uv_stream_t *) client, (uv_alloc_cb)alloc_buffer, read_cb);
if (r) {
printf("error 3n");
}
state_->onConnect();
} else {
/* close client stream on error */
uv_close((uv_handle_t *) client, NULL);
}
}
};
CB cb;
uv_tcp_t server;
uv_loop_t * loop;
int main() {
loop = uv_default_loop();
/* convert a humanreadable ip address to a c struct */
struct sockaddr_in addr;
uv_ip4_addr("127.0.0.1", 3005, &addr);
/* initialize the server */
uv_tcp_init(loop, &server);
/* bind the server to the address above */
uv_tcp_bind(&server, (const struct sockaddr *)&addr, 0);
/* let the server listen on the address for new connections */
int r = uv_listen((uv_stream_t *) &server, 128, (uv_connection_cb)&cb);
if (r) {
printf("error 1n");
return -1;
}
/* execute all tasks in queue */
return uv_run(loop, UV_RUN_DEFAULT);
}
/**
* Callback which is executed on each new connection.
*/
void connection_cb(uv_stream_t * server, int status) {
/* dynamically allocate a new client stream object on conn */
uv_tcp_t * client = (uv_tcp_t *)malloc(sizeof(uv_tcp_t));
/* if status not zero there was an error */
if (status == -1) {
printf("error 2n");
}
/* initialize the new client */
uv_tcp_init(loop, client);
/* now let bind the client to the server to be used for incomings */
if (uv_accept(server, (uv_stream_t *) client) == 0) {
/* start reading from stream */
//int r = uv_read_start((uv_stream_t *) client, (uv_alloc_cb)alloc_buffer, read_cb);
int r = 0;
if (r) {
printf("error 3n");
}
} else {
/* close client stream on error */
uv_close((uv_handle_t *) client, NULL);
}
}
/**
* Callback which is executed on each readable state.
*/
void read_cb(uv_stream_t * stream, ssize_t nread, uv_buf_t buf) {
/* dynamically allocate memory for a new write task */
uv_write_t * req = (uv_write_t *) malloc(sizeof(uv_write_t));
/* if read bytes counter -1 there is an error or EOF */
if (nread == -1) {
printf("error 4n");
uv_close((uv_handle_t *) stream, NULL);
}
/* write sync the incoming buffer to the socket */
int r = uv_write(req, stream, &buf, 1, NULL);
if (r) {
printf("error 5n");
}
}
/**
* Allocates a buffer which we can use for reading.
*/
uv_buf_t alloc_buffer(uv_handle_t * handle, size_t size) {
return uv_buf_init((char *) malloc(size), size);
}
粘贴的代码将不起作用,因为libuv需要uv_listen
中的函数指针——您提供的是指向结构的指针。这个结构恰好有一个operator()
,但这并不能使结构的地址成为处理器可以跳转到并执行代码的地址。operator()
与结构的任何其他方法一样,但您可以简单地使用()
或.operator()
进行调用,以提高代码的可读性。此外,由于operator()
是非静态的,它期望对this
的隐式引用,而libuv不会提供,因为它不期望必须提供。
为了实现您想要做的事情,您应该提供一个普通的C函数回调,并将额外的上下文数据存储在句柄的.data
字段中:
代替:
int r = uv_listen((uv_stream_t *) &server, 128, (uv_connection_cb)&cb);
用途:
server.data = &cb;
int r = uv_listen((uv_stream_t *) &server, 128, [](uv_stream_t *server, int status){
(*(CB*)server->data)(server, status);
});
uv控制柄上的.data
字段正是为此目的而提供的。
相关文章:
- 以特征类型作为参数的泛型函数回调
- C# DllImport 调用非托管C++函数回调
- 为什么模板参数推导失败,std::函数回调的可变参数模板参数?
- std::包含 std::函数回调的多个包装器的向量不起作用
- 如何设置对类的私有函数的函数回调?
- 如何使用 c++11 函数回调声明多个模板参数
- sqlite3 更改函数回调参数 void* not用于 int* C++
- 如何知道 sqlite 中的函数"回调"是否返回了一些东西?
- Windows表单如何使用其他函数回调图表信息
- 如何在 c++ 结构中的 void* 变量中调用存储函数(回调)
- 将成员函数作为标准函数回调
- C++ 使用成员函数回调实现按钮
- std::函数回调,参数采用观察者模式(寄存器主题上的占位符)
- 使用可变参数模板从 Lua 函数回调 (C api) 中提取参数
- 在C++中使用派生类的静态方法作为函数回调
- 将libuv与函数结构一起使用,而不是函数回调
- 如何将函数回调传递给类成员
- c++类成员函数回调
- C++函数回调:无法从成员函数转换为函数签名
- 如何编写一个通用函数回调测试类