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

raw socket中recvfrom()持续返回-1(错误:Resource temporarily unavailable),无法接收ARP响应包

raw socket中recvfrom()持续返回-1(错误:Resource temporarily unavailable),无法接收ARP响应包

兄弟,别慌!作为过来人,我太懂初学者遇到这种socket错误的崩溃感了,咱们一步步来排查解决这个问题~

首先,你遇到的Resource temporarily unavailable错误,本质上对应系统错误码EAGAIN/EWOULDBLOCK,常见原因无非这几个:套接字是非阻塞模式、接收时机太早(响应还没到)、绑定/过滤逻辑有问题,或者最容易被忽略的——没加root权限运行!

先给你几个立刻能试的修复步骤:


1. 确保套接字是阻塞模式(最可能的直接原因)

你创建的raw套接字可能被默认设置成了非阻塞模式,导致你刚发完包就调用recvfrom时,响应还没到就直接返回错误。在CreateRawSocket函数里,创建完套接字后添加这段代码,强制设置为阻塞模式:

int CreateRawSocket() {
    int sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
    if(sockfd == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    // 新增:强制设置为阻塞模式
    int flags = fcntl(sockfd, F_GETFL, 0);
    if (flags == -1) {
        perror("fcntl get flags");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    flags &= ~O_NONBLOCK; // 清除非阻塞标志
    if (fcntl(sockfd, F_SETFL, flags) == -1) {
        perror("fcntl set block");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    return sockfd;
}

这样recvfrom会一直阻塞,直到有ARP包到达,而不是直接返回错误。

2. 必须用root权限运行程序!

raw套接字是需要系统特权的,普通用户根本没有权限绑定或接收raw包。别忘记用sudo运行你的可执行文件,比如:

sudo ./your_arpscanner 192.168.1.100

这一步90%的初学者都会忘,一定要记牢!

3. 检查ListenPacket函数的recvfrom调用是否正确

你没贴这个函数的实现,但我猜你可能没正确设置sockaddr_ll的长度参数。正确的接收逻辑应该是这样的:

void ListenPacket(int sockfd, unsigned char* packet, struct Config* cfg) {
    struct sockaddr_ll src_addr;
    socklen_t addr_len = sizeof(src_addr); // 必须传入指针,recvfrom会修改它
    ssize_t recv_len = recvfrom(sockfd, packet, PACKETLEN, 0, 
                                (struct sockaddr*)&src_addr, &addr_len);
    if (recv_len == -1) {
        perror("recvfrom");
        exit(EXIT_FAILURE);
    }

    // 额外:过滤只接收目标是自己MAC的ARP响应
    struct ethhdr* received_ehdr = (struct ethhdr*)packet;
    struct myarphdr* received_ahdr = (struct myarphdr*)(packet + sizeof(struct ethhdr));
    if (memcmp(received_ehdr->h_dest, cfg->src_mac, ETH_ALEN) == 0 && 
        ntohs(received_ahdr->operation) == ARPOP_REPLY) {
        printf("Received valid ARP reply!\n");
        PrintMAC(received_ahdr->sender_mac);
        PrintIP(&received_ahdr->sender_ip);
    }
}

重点是addr_len必须是一个指向socklen_t变量的指针,不能直接传sizeof(src_addr),否则recvfrom会报错。

4. 确认绑定的网卡接口正确

你硬编码了"wlo1",先通过ip link show命令确认这个接口名是否正确,比如是不是wlp2s0之类的?如果接口名错了,绑定会失败,自然收不到包。另外,if_nametoindex返回0的问题,大概率也是因为普通用户权限不够,用sudo跑的话应该能正常返回接口索引。

额外的初学者小贴士:

  • 发送ARP请求后,不要只接收一次,最好加个循环+超时逻辑,比如循环接收3次,每次间隔1秒,避免因为网络延迟漏收响应。
  • 抓包工具能看到响应但程序收不到,就检查套接字的过滤规则:你绑定的是ETH_P_ARP,内核只会把ARP包传给你,这个是对的,但如果有其他进程也在监听ARP包,会不会被抢走?不过这种情况很少见。
  • 检查你的ARP包构造是否正确:比如以太网头的目标MAC是不是广播MAC(ff:ff:ff:ff:ff:ff),ARP头的操作码是不是ARPOP_REQUEST(1),目标MAC是不是全0,这些错了的话对方可能不会响应。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 07:24:30