libuv报错:未初始化流问题排查及代码求助
问题分析与修复方案
嘿,我一眼就瞅出你这问题的根源了——不是流没初始化,是TCP客户端对象的内存生命周期出问题啦!
为啥会触发这个断言?
看你SendData函数里的这段代码:
void SendData( uv_async_t*sd ) { uv_tcp_t client; // 划重点:这是个局部栈变量! uv_tcp_init(loop, &client); uv_connect_t* connect = (uv_connect_t*)malloc(sizeof(uv_connect_t)); // ... 其他代码 uv_tcp_connect(connect, &client, ..., OnConnectToServer); }
uv_tcp_t client是SendData函数里的局部变量,当SendData执行完返回时,栈上的这个变量会被直接回收,内存变成无效状态。但uv_tcp_connect是异步操作,OnConnectToServer回调要到连接完成后才会执行,这时候你通过client->handle拿到的已经不是合法的uv_tcp_t对象了,uv_write检查流类型时自然就触发了断言错误。
怎么修复?
你得把客户端对象的内存分配到堆上,确保在回调执行时它还活着。我给你改了代码,还加了个自定义结构体把连接请求和客户端对象绑定在一起,方便回调里拿数据:
// 自定义结构体,把连接请求和客户端对象绑定 typedef struct { uv_connect_t connect_req; uv_tcp_t client; } client_connect_t; void OnConnectToServer(uv_connect_t *connect_req, int status) { if (status < 0) { // 连接失败,记得释放堆内存 client_connect_t *client_conn = (client_connect_t*)connect_req->data; free(client_conn); return; } printf( "Client attempt write\n" ); write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t)); req->buf = uv_buf_init( (char*) malloc(1), 1 ); (req->buf.base)[0] = '0'; // 从connect_req的data字段拿到对应的客户端对象 client_connect_t *client_conn = (client_connect_t*)connect_req->data; // 把uv_tcp_t转成uv_stream_t,这在libuv里是合法的继承转换 uv_write((uv_write_t*) req, (uv_stream_t*)&client_conn->client, &req->buf, 1, OnWrite); } void SendData( uv_async_t*sd ) { // 给自定义结构体分配堆内存 client_connect_t *client_conn = (client_connect_t*)malloc(sizeof(client_connect_t)); if (!client_conn) return; // 内存分配失败直接返回 uv_tcp_init(loop, &client_conn->client); // 把自定义结构体和connect_req绑定,方便回调里获取 client_conn->connect_req.data = client_conn; struct sockaddr_in dest; uv_ip4_addr("192.168.20.3", PORT, &dest); uv_tcp_connect(&client_conn->connect_req, &client_conn->client, (const struct sockaddr*)&dest, OnConnectToServer); }
额外提醒
- 别忘了在
OnWrite回调里也要释放write_req_t和buf的内存,还有后续客户端关闭时要释放client_connect_t的内存,别造成内存泄漏! - libuv里的
uv_tcp_t是继承自uv_stream_t的,所以强制类型转换是安全的,这也是libuv官方推荐的用法。
内容的提问来源于stack exchange,提问作者dinner
相关产品推荐
相关产品推荐

