Conversation
Update icmp.c
There was a problem hiding this comment.
Pull request overview
该 PR 针对 protocol/icmp.c 中 ping() 在收到无效 ICMP 包时的统计与等待逻辑进行修复,目标是在出现无效包时继续等待有效的 echo reply,并避免把无效包计入“received”统计。
Changes:
- 新增按“单次 ping 请求”维度的接收重试逻辑:无效包时继续接收,超时后进入下一次发送
- 将
recv_cnt的统计调整为仅在收到有效 echo reply 时递增,修正统计异常 - 引入
cur_ping_start_tick用于控制单次 ping 的等待窗口
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| _read_again: | ||
| if(gettick_ms() - cur_ping_start_tick >= PING_TIMEOUT) { | ||
| // recv timeout, send ping again. | ||
| continue; | ||
| } | ||
|
|
||
| int nrecv = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, &peeraddr.sa, &addrlen); | ||
| if (nrecv < 0) { |
There was a problem hiding this comment.
当前 _read_again 重试逻辑里每次都会再次调用带 SO_RCVTIMEO=PING_TIMEOUT 的 recvfrom()。如果在接近 1s 末尾收到一个无效包(例如 900ms),会马上进入下一次 recvfrom(),它又可能再阻塞 1s,导致单次 ping 实际等待时间超过 PING_TIMEOUT(最多接近 2*PING_TIMEOUT),与“1s 内收不到有效 echo 就发下一个”的目标不符。建议按截止时间计算剩余超时(remaining = PING_TIMEOUT - elapsed)并把 SO_RCVTIMEO 设置为 remaining 后再 recvfrom,或改用 poll/select 按 deadline 等待。
| int nrecv = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, &peeraddr.sa, &addrlen); | ||
| if (nrecv < 0) { | ||
| perror("recvfrom"); | ||
| continue; | ||
| goto _read_again; |
There was a problem hiding this comment.
recvfrom() 失败后无条件 perror 并 goto _read_again,会在非超时/中断类错误(例如 EBADF、EINVAL 等)时循环打印并拖到 PING_TIMEOUT 才进入下一轮,掩盖真实错误。建议仅在 errno 为 EINTR / EAGAIN(EWOULDBLOCK) / ETIMEDOUT 时重试;其他错误应直接退出循环并走 error 路径或返回错误码。
| } | ||
| ++recv_cnt; | ||
|
|
||
| end_hrtime = gethrtime_us(); |
There was a problem hiding this comment.
end_hrtime 在校验前(line 95)和校验通过后(line 112)被赋值两次,但只有后一次用于计算 rtt。建议删除前一次赋值,避免冗余并减少误解。
| end_hrtime = gethrtime_us(); |
| ++send_cnt; | ||
| addrlen = sizeof(peeraddr); | ||
| _read_again: | ||
| if(gettick_ms() - cur_ping_start_tick >= PING_TIMEOUT) { |
There was a problem hiding this comment.
这里的代码风格与本文件其他 if 语句不一致:使用了 if( 而不是 if (。建议保持一致的空格风格。
| if(gettick_ms() - cur_ping_start_tick >= PING_TIMEOUT) { | |
| if (gettick_ms() - cur_ping_start_tick >= PING_TIMEOUT) { |
【问题】
该IP是可以被ping通的,但是在ping过程中收到无效包,程序并没有再继续等待ping echo,而是继续发送ping req,导致后面回来的ping echo没有被标记为ok
root@localhost:/share/wenqikai# ./ping 5.5.12.101
64 bytes from 5.5.12.101: icmp_seq=1 ttl=64 time=0.5 ms
recv invalid icmp packet!
recv invalid icmp packet!
recv invalid icmp packet!
--- 5.5.12.101 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 1002 ms(--> 收到4个包, 没有丢失,实际上把无效包也统计在内了)
rtt min/avg/max = 0.460/0.460/0.460 ms
ping 4 count, 1 ok.(--> 这里显示只有1个有效包)
【解决方案】
收到无效包时,继续接收ping echo。如1s内未接收不到有效ping echo包,再发送下一个ping req