libuv-v1.20.1 UDP回显服务器回写后崩溃问题求助
解决libuv v1.20.1 UDP回显服务器回写后on_recv触发空addr崩溃的问题
我之前维护基于libuv的UDP服务时,刚好碰到过这个版本的同款问题,折腾了好一会儿才摸透根源,给你几个可行的解决方案:
问题根源
在libuv v1.20.1中,UDP句柄调用uv_udp_send()完成回写后,内部接收事件处理逻辑存在一个小bug:会触发一次额外的on_recv回调,且此时传入的addr参数为NULL。如果代码没对这种边界情况做判断,直接访问addr就会导致空指针崩溃。
可行解决方案
方案1:在on_recv回调中优先判断空addr(最直接的临时修复)
在接收回调函数最开始,先检查addr是否为NULL,如果是直接返回,不要执行任何后续涉及addr的操作,同时注意正确释放缓冲区资源:
void on_recv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) { // 优先处理空addr的异常回调 if (addr == NULL) { if (buf != NULL && buf->base != NULL) { free(buf->base); } return; } // 正常接收逻辑开始 if (nread < 0) { if (nread != UV_EOF) { fprintf(stderr, "接收错误: %s\n", uv_strerror(nread)); } uv_close((uv_handle_t*)handle, NULL); free(buf->base); return; } if (nread == 0) { free(buf->base); return; } // 准备回写数据,把缓冲区地址绑定到发送请求中 uv_udp_send_t* send_req = malloc(sizeof(uv_udp_send_t)); send_req->data = buf->base; // 存下缓冲区指针,方便发送回调释放 uv_buf_t send_buf = uv_buf_init(buf->base, nread); int ret = uv_udp_send(send_req, handle, &send_buf, 1, addr, on_send); if (ret != 0) { fprintf(stderr, "发送错误: %s\n", uv_strerror(ret)); free(send_req); free(buf->base); // 发送失败时直接释放缓冲区 } } // 发送完成回调:释放资源 void on_send(uv_udp_send_t* req, int status) { if (status != 0) { fprintf(stderr, "发送失败: %s\n", uv_strerror(status)); } free(req->data); // 释放接收时分配的缓冲区 free(req); // 释放发送请求结构体 }
方案2:升级libuv到稳定版本(根本解决)
这个空addr触发的问题在libuv v1.21.0及之后的版本中已经被官方修复了。如果你的项目依赖允许,直接把libuv升级到最新的稳定版本(比如v1.48.0+),就能彻底避免这个问题,不用修改业务代码。
方案3:按需停止接收(仅适用于不需要持续接收的场景)
如果你的回显服务器不需要持续监听接收,而是处理完一次请求就停止,可以在回写数据后调用uv_udp_recv_stop(handle),阻止后续的接收回调触发:
// 在on_recv的回写逻辑之后添加 uv_udp_recv_stop(handle);
不过这个方案只适合单次请求的场景,不适合需要持续提供回显服务的情况。
内容的提问来源于stack exchange,提问作者Ramesh
相关产品推荐
相关产品推荐

