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

C语言实现ping程序时recvfrom()异常收到出站ICMP请求包问题求助

问题根因

你使用的是ICMP类型的原始套接字,这类套接字的默认工作机制是捕获本机所有匹配协议的报文,包括你自己程序发出去的出站ICMP回显请求(type=8),也包括从环回口/物理网卡收到的入站ICMP回显应答(type=0)。你ping环回地址时,自己发的请求会先进入接收队列,之后才是内核返回的应答,所以就出现了奇数次调用recvfrom拿到请求、偶数次拿到应答的规律。

可行解决方案

方案1(通用跨平台,最推荐)

在接收逻辑中增加报文过滤规则,只有同时满足以下所有条件的报文才视为有效应答,否则直接丢弃并继续调用recvfrom读取下一个报文:

  • ICMP报文类型为0(回显应答)
  • ICMP报文中的标识符字段和你发送请求时填写的标识符完全一致(一般用当前进程PID作为标识符,可避免和系统中其他ping进程的报文冲突)
  • ICMP报文的序列号和本次发送的请求序列号匹配

修改后的接收逻辑参考:

// Receive
struct timeval timeout = {3, 0};//3s
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
while(1) {
    if ((n = recvfrom(sockfd, buf, BUF_SIZE, 0, (struct sockaddr *) &from, &fromlen)) < 0) {
        printf("Time out! \n");
        // 超时跳出循环
        break;
    }
    // 解包后判断是否是本次期望的应答
    int ret = unpack(buf, n);
    if (ret == 0) {
        // 是有效应答,计数后跳出循环
        nreceived++;
        break;
    } else if (ret == -1) {
        // 不是目标应答,继续读下一个报文
        continue;
    }
}

你只需要在unpack函数中补充上面提到的类型、标识符、序列号校验逻辑,校验不通过返回-1即可。

方案2(Linux平台专用,性能更高)

可以给原始套接字挂载BPF(伯克利包过滤)规则,直接在内核层面过滤掉不符合要求的报文,减少用户态内存拷贝的开销。
核心配置代码参考:

// 构造过滤ICMP回显应答、且标识符为当前进程PID的BPF规则
struct sock_filter bpf_code[] = {
    // 加载ICMP类型字段
    BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct icmphdr, type)),
    // 判断是否是回显应答(type=0),不是就丢弃
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ICMP_ECHOREPLY, 1, 0),
    BPF_STMT(BPF_RET + BPF_K, 0),
    // 加载ICMP标识符字段
    BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct icmphdr, un.echo.id)),
    // 判断是否是本进程的ID,不是就丢弃
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, htons(getpid()), 1, 0),
    BPF_STMT(BPF_RET + BPF_K, 0),
    // 匹配成功,返回全报文
    BPF_STMT(BPF_RET + BPF_K, (u_int)-1),
};
struct sock_fprog bpf_prog = {
    .len = sizeof(bpf_code)/sizeof(bpf_code[0]),
    .filter = bpf_code,
};
// 给套接字挂载过滤规则
setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf_prog, sizeof(bpf_prog));

内容的提问来源于stack exchange,提问作者Fresher

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 13:06:08