Android中Netlink socket的recv()调用失败(errno=11)求助
Android NDK下Netlink Socket获取ARP缓存时recv返回-1(错误码11)的排查方案
相同代码在Linux主机上运行正常,但在Android NDK原生C++环境中调用recv()时始终返回-1,错误码为11(对应EAGAIN,表示资源暂时不可用)。下面针对问题代码逐一排查:
问题代码
struct sockaddr_nl saddr; int m_fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); memset(&saddr, 0, sizeof(saddr)); saddr.nl_family = AF_NETLINK; saddr.nl_pid = getpid(); if(m_fd<0) { fprintf(stderr, "socket error: \n"); __android_log_print(ANDROID_LOG_ERROR, "LOG", "socket error %d", errno); exit(EXIT_FAILURE); } else { __android_log_print(ANDROID_LOG_ERROR, "LOG", "socket success %d", m_fd); } struct { struct nlmsghdr nlh; struct rtmsg rtm; } nl_request; nl_request.nlh.nlmsg_type = RTM_GETNEIGH; nl_request.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; nl_request.nlh.nlmsg_pid = getpid(); nl_request.nlh.nlmsg_len = sizeof(nl_request); nl_request.nlh.nlmsg_seq = 0; nl_request.rtm.rtm_family = AF_INET; int sent = send(m_fd, &nl_request, sizeof(nl_request), 0); if (sent < 0 ) { __android_log_print(ANDROID_LOG_ERROR, "LOG", "request error"); __android_log_print(ANDROID_LOG_ERROR, "LOG", "%d",errno ); } else { __android_log_print(ANDROID_LOG_ERROR, "LOG", "request success %d", sent); } struct nlmsghdr *h; int status; char resp[1024]; static char buffer[RECEIVE_BUFFER_LEN] = {0}; __android_log_print(ANDROID_LOG_ERROR, "LOG", "buffer length: %d",RECEIVE_BUFFER_LEN); memset(buffer, 0, sizeof(buffer)); /* Check for immediate errors */ status = recv(m_fd, &buffer, sizeof(buffer), MSG_DONTWAIT | MSG_PEEK); if (status < 0) { __android_log_print(ANDROID_LOG_ERROR, "LOG", "recv_len < 0: %d, errno: %d", status, errno); } else { __android_log_print(ANDROID_LOG_ERROR, "LOG", "recv_len > 0 : %d", status); }
排查与解决步骤
缺失Socket绑定操作
Android的Netlink实现对地址绑定的要求比标准Linux更严格,代码中仅初始化了saddr但未调用bind()绑定本地地址,会导致无法正确接收内核响应。需要在send()前添加绑定逻辑:if (bind(m_fd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) { __android_log_print(ANDROID_LOG_ERROR, "LOG", "bind failed, errno: %d", errno); close(m_fd); exit(EXIT_FAILURE); }权限限制
Android的SELinux会限制普通应用访问Netlink路由消息的权限:- 在AndroidManifest.xml中添加权限声明:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> - Android 10及以上版本可能需要额外的
ACCESS_WIFI_STATE权限,或者在root设备上测试以排除权限问题。
- 在AndroidManifest.xml中添加权限声明:
非阻塞读取逻辑问题
错误码11是EAGAIN,表示当前无数据可读。你使用了MSG_DONTWAIT | MSG_PEEK非阻塞方式读取,但Netlink响应不会立即返回,建议恢复循环读取逻辑并处理EAGAIN:do { status = recv(m_fd, buffer, sizeof(buffer), 0); if (status < 0) { if (errno != EINTR && errno != EAGAIN) { __android_log_print(ANDROID_LOG_ERROR, "LOG", "recv error: %d", errno); break; } } } while (status < 0);同时建议移除
MSG_PEEK(仅查看数据不消费,会导致后续重复读取),并确保RECEIVE_BUFFER_LEN足够大(比如设置为8192),避免缓冲区溢出。Netlink请求参数补全
部分Android设备需要明确设置rtmsg的额外参数,避免内核忽略请求:nl_request.rtm.rtm_scope = RT_SCOPE_UNIVERSE; nl_request.rtm.rtm_protocol = RTPROT_UNSPEC; nl_request.nlh.nlmsg_seq = time(NULL); // 设置唯一序列号,避免响应混淆
内容的提问来源于stack exchange,提问作者Jongyong Park
相关产品推荐
相关产品推荐

