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
相关产品推荐
相关产品推荐

