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

发送ICMP_ECHO后recvmsg阻塞返回EAGAIN问题求助

简易Ping命令针对google.com出现recvmsg阻塞超时问题

我正在实现一个简易版ping命令,已成功解析目标地址(测试地址为www.google.com),使用sendto(2)发送ICMP_ECHO请求,但接收流程中recvmsg(2)函数持续阻塞,超时后返回EAGAIN错误。其他网站均可正常运行,不确定是ICMP头部设置不当还是recvmsg参数存在问题。

发送ICMP_ECHO请求的代码

void send_v4()
{
  char buff[64];
  struct icmp *icmp;

  // Setup the ICMP packet header
  icmp = (struct icmp *)buff;
  icmp->icmp_id    = getpid();
  icmp->icmp_type  = ICMP_ECHO;
  icmp->icmp_code  = 0;
  icmp->icmp_seq   = 1;
  memset(icmp->icmp_data, 0x00, 56);

  // Setup data section
  gettimeofday((struct timeval *)(icmp->icmp_data), NULL);

  // Send full packet
  int ret = sendto(proto_v4.sockfd, buff, sizeof(buff), 0, proto_v4.dst_sa, proto_v4.dst_ai->ai_addrlen);
  if (ret == -1)
  printf("sendto failed with error code: %d\n", ret);
}

接收响应的代码

void proc_v4()
{
        char buff[256];
        ssize_t received;
        struct iovec iov;
        struct msghdr msghdr;
        struct ip *ip;
        struct icmp *icmp;
        struct timeval tvcurr;
        struct timeval tvrecv;
        double time;

        memset(buff, 0x00, 256);

        iov.iov_base = buff;
        iov.iov_len = sizeof(buff);

        msghdr.msg_iov = &iov;
        msghdr.msg_iovlen = 1;

        received = recvmsg(proto_v4.sockfd, &msghdr, 0);
        if (received == -1)
                perror("recvmsg");

        ip = (struct ip *)(iov.iov_base);
        if (ip->ip_p == IPPROTO_ICMP)
                printf("IPPROTO_ICMP\n");

        icmp = (struct icmp *)(iov.iov_base + (ip->ip_hl << 2));
        if (icmp->icmp_type == ICMP_ECHOREPLY)
                printf("ICMP_ECHOREPLY %d\n", icmp->icmp_id);

        char buf[256];
        inet_ntop(
                proto_v4.dst_ai->ai_family,
                &((struct sockaddr_in *)proto_v4.dst_sa)->sin_addr,
                buf,
                256
        );

        tvrecv = *(struct timeval *)(icmp->icmp_data);

        gettimeofday(&tvcurr, NULL);
        time  = (tvcurr.tv_sec  - tvrecv.tv_sec)  * 1000;
        time += (tvcurr.tv_usec - tvrecv.tv_usec) / 1000.0;
        printf("%ld %ld\n", (tvcurr.tv_usec - tvrecv.tv_usec), (tvcurr.tv_usec - tvrecv.tv_usec) % 1000);
        printf("%d bytes from %s (%s): icmp_seq=%d ttl=%d time=%.2lf ms\n", 64, buf, buf, icmp->icmp_seq, ip->ip_ttl, time);
}

问题排查方向

  • ICMP校验和缺失:发送的ICMP包未计算校验和,Google服务器可能丢弃校验错误的包。需补充校验和计算:icmp->icmp_cksum = in_cksum((unsigned short *)icmp, sizeof(buff));(需实现标准ICMP校验和函数)。
  • recvmsg参数不完整:msghdr未初始化msg_name和msg_namelen字段,原始套接字需接收源地址以匹配响应包。应添加:
    struct sockaddr_in src_addr;
    memset(&msghdr, 0, sizeof(msghdr));
    msghdr.msg_name = &src_addr;
    msghdr.msg_namelen = sizeof(src_addr);
    
  • TTL设置过低:默认TTL可能导致数据包中途被丢弃,可通过setsockopt设置TTL为64或128:
    int ttl = 64;
    setsockopt(proto_v4.sockfd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
    
  • 网络限制:Google可能对ICMP请求有速率限制,可增加发送间隔,或检查本地防火墙是否拦截ICMP响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 04:05:19