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

