You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中Netlink socket的recv()调用失败(errno=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设备上测试以排除权限问题。
  • 非阻塞读取逻辑问题
    错误码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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 16:20:31