当前位置: 首页 > news >正文

简单理解:ICMP 是什么?

1.ICMP = Internet Control Message Protocol互联网控制报文协议

一句话:它不是用来传用户数据的,是用来给 IP 网络 “报信、报错、检测” 的。

2. 最常见的用途

(1)Ping 命令

你平时用的ping命令,底层就是 ICMP

  • 发一个 ICMP 回显请求(Echo Request)
  • 对方回复 ICMP 回显应答(Echo Reply)用来测:通不通、延迟多少、丢包不丢包

(2)报告网络错误

比如:

  • 目标主机不可达(Destination Unreachable)
  • 数据包超时(Time Exceeded)
  • 路由重定向(Redirect)这些都是 ICMP 发给你的错误提示。

3. 它在协议栈里的位置

  • IP 层协议(在 TCP/UDP 下面一层)
  • 不依赖端口,只依赖 IP 地址
应用层(HTTP、MQTT) 传输层(TCP、UDP) 网络层(IP + ICMP + IGMP) 数据链路层(以太网、CAN……)

4. 和 TCP/UDP 的区别(重点)

  • TCP/UDP:传用户数据(文件、视频、指令)
  • ICMP:传网络状态、错误、检测
  • ICMP不建立连接不保证可靠没有端口号

5. 嵌入式里什么时候会遇到?

  • 以太网 / WiFi 联网(STM32+LAN8720、ESP32)
  • 想实现ping 功能,就要开 ICMP
  • LwIP 协议栈里默认就带 ICMP,一般不用自己写

超简总结

  • ICMP = 网络的 “诊断 + 报错” 协议
  • 最典型代表:ping
  • 不和你发数据,只告诉你:通不通、哪断了、超时了。

LwIP 是嵌入式领域最常用的轻量级 TCP/IP 协议栈,其 ICMP 实现核心代码集中在icmp.c/icmp.h文件中,我会提取核心关键代码(基于 LwIP 2.1.2 版本,最稳定的主流版本),并逐行解释关键逻辑,适配 STM32 等嵌入式场景:

一、先明确核心文件与功能

文件核心作用
src/core/icmp.cICMP 报文的接收、解析、响应(如 Ping)
src/core/icmp.hICMP 宏定义、函数声明(如回显请求 / 应答)
src/core/def.hICMP 报文类型、代码的宏定义(如 ECHO_REQUEST)

二、核心代码提取 + 逐行解释

1. ICMP 核心宏定义(icmp.h)

先看协议层面的关键宏,对应 ICMP 报文格式:

/* icmp.h 中核心宏定义 */ /* ICMP 报文类型 */ #define ICMP_ER 0 // 回显应答(Ping响应) #define ICMP_ECHO 8 // 回显请求(Ping请求) #define ICMP_DEST_UNREACH 3// 目标不可达 #define ICMP_TIME_EXCEEDED 11// 超时 /* ICMP 报文结构体(简化版,对应Ping包) */ struct icmp_echo_hdr { u8_t type; // 类型(8=请求,0=应答) u8_t code; // 代码(通常0) u16_t chksum; // 校验和 u16_t id; // Ping ID(匹配请求/应答) u16_t seqno; // Ping 序列号 /* 后面跟着数据段(可选,比如Ping的测试数据) */ }; /* 函数声明:ICMP 报文接收处理 */ void icmp_input(struct pbuf *p, struct netif *inp);

2. ICMP 核心处理函数(icmp.c)

icmp_input是 ICMP 报文的入口函数(网卡收到 ICMP 包后调用),核心逻辑是解析 Ping 请求并回复 Ping 应答

/* icmp.c 核心函数:处理收到的ICMP报文 */ void icmp_input(struct pbuf *p, struct netif *inp) { struct icmp_echo_hdr *icmphdr; u16_t chksum; ip_addr_t tmpaddr; /* 1. 校验pbuf(数据包缓存)有效性,至少包含ICMP头部 */ if (p->len < sizeof(struct icmp_echo_hdr)) { pbuf_free(p); // 包太短,释放缓存 return; } /* 2. 提取ICMP头部指针(pbuf->payload是数据包起始地址) */ icmphdr = (struct icmp_echo_hdr *)p->payload; /* 3. 校验ICMP校验和(防止数据包损坏) */ chksum = inet_chksum(icmphdr, p->len); if (chksum != 0) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed\n")); pbuf_free(p); return; } /* 4. 根据ICMP类型分支处理(核心:Ping请求响应) */ switch (icmphdr->type) { /* -------------- 处理Ping请求(ICMP_ECHO=8)-------------- */ case ICMP_ECHO: /* 4.1 检查是否开启Ping响应(嵌入式可配置关闭) */ if (sys_get_from_ip_if(inp, IPV4_ADDR_ANY) == 0) { pbuf_free(p); return; } /* 4.2 把请求类型改为应答(8→0) */ icmphdr->type = ICMP_ER; /* 4.3 重新计算校验和(类型变了,校验和需更新) */ icmphdr->chksum = 0; // 先清零 icmphdr->chksum = inet_chksum(icmphdr, p->len); /* 4.4 交换源/目的IP(把请求的源IP作为应答的目的IP) */ tmpaddr = ip_current_dest_addr(); ip_current_dest_addr_set(ip_current_src_addr()); ip_current_src_addr_set(tmpaddr); /* 4.5 发送ICMP应答(核心:调用IP层发送函数) */ ip_output_if(p, &ip_current_dest_addr(), IP_HDRINCL, ICMP_TTL, IP_PROTO_ICMP, inp); break; /* -------------- 其他ICMP类型(简化版,仅保留关键)-------------- */ case ICMP_DEST_UNREACH: // 目标不可达 case ICMP_TIME_EXCEEDED: // 超时 LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: unhandled ICMP type %d\n", icmphdr->type)); pbuf_free(p); break; /* -------------- 未知类型 -------------- */ default: LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: unknown ICMP type %d\n", icmphdr->type)); pbuf_free(p); break; } }

3. 辅助函数:Ping 请求发送(可选,主动 Ping)

如果需要嵌入式主动 Ping 其他设备(如网关),核心函数icmp_send_echo

/* icmp.c:发送ICMP回显请求(主动Ping) */ err_t icmp_send_echo(const ip_addr_t *addr, u16_t id, u16_t seqno, u8_t ttl) { struct pbuf *p; struct icmp_echo_hdr *icmphdr; /* 1. 分配pbuf缓存(LwIP核心数据结构,存储数据包) */ p = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr), PBUF_RAM); if (p == NULL) { return ERR_MEM; // 内存不足 } /* 2. 填充ICMP头部 */ icmphdr = (struct icmp_echo_hdr *)p->payload; icmphdr->type = ICMP_ECHO; // 类型:回显请求 icmphdr->code = 0; // 代码:0(无附加信息) icmphdr->chksum = 0; // 先清零,后面计算 icmphdr->id = id; // Ping ID(自定义,如0x1234) icmphdr->seqno = seqno; // 序列号(递增,如1、2、3) /* 3. 计算校验和 */ icmphdr->chksum = inet_chksum(icmphdr, p->len); /* 4. 发送ICMP包(调用IP层发送) */ return ip_output(p, addr, ttl, 0, IP_PROTO_ICMP); }

4. STM32 中启用 ICMP(关键配置)

在 LwIP 配置文件lwipopts.h中开启 ICMP(默认开启,需确认):

/* lwipopts.h:启用ICMP/Ping功能 */ #define LWIP_ICMP 1 // 开启ICMP模块 #define ICMP_ECHO 1 // 开启Ping响应(允许被Ping) #define ICMP_TTL 64 // ICMP报文TTL(默认64) #define LWIP_CHECKSUM_ON_COPY 1 // 硬件校验和(STM32推荐开启)

三、核心逻辑梳理(嵌入式视角)

1. 被动 Ping(STM32 被电脑 Ping)流程

2. 主动 Ping(STM32 Ping 网关)流程

// STM32代码示例:主动Ping网关(192.168.1.1) ip_addr_t gw_addr; IP4_ADDR(&gw_addr, 192, 168, 1, 1); // 发送Ping请求:ID=0x1234,序列号=1,TTL=64 icmp_send_echo(&gw_addr, 0x1234, 1, 64);

四、嵌入式适配关键注意事项

  1. pbuf 内存管理:LwIP 中pbuf_alloc是核心,STM32 需配置内存池大小(MEM_SIZE),避免 Ping 包分配失败;
  2. 校验和优化:STM32 以太网外设(如 LAN8720)支持硬件校验和,开启LWIP_CHECKSUM_ON_COPY可减少 CPU 占用;
  3. 中断 / 线程配合:ICMP 处理建议放在 LwIP 的tcpip_thread线程中(默认如此),避免在中断中直接处理;
  4. 资源限制:嵌入式中关闭不必要的 ICMP 类型(如目标不可达、超时),仅保留ICMP_ECHO/ICMP_ER,节省内存。

总结(核心关键点)

  1. LwIP 的 ICMP 核心是icmp_input(处理接收)和icmp_send_echo(处理发送);
  2. Ping 响应的核心逻辑:解析请求→修改类型→重算校验和→交换 IP→发送应答
  3. STM32 中只需开启LWIP_ICMP=1,无需修改核心代码,即可实现 Ping 功能;
  4. 嵌入式场景下重点关注pbuf内存分配和硬件校验和优化,保证 Ping 响应稳定。
http://www.jsqmd.com/news/512817/

相关文章:

  • 免费配音软件推荐2026,这5款真的不踩坑
  • 南京口碑好殡葬服务机构专业推荐 - 资讯焦点
  • 2026年绩效管理咨询公司推荐:集团型企业构建高绩效体系口碑机构分析 - 品牌推荐
  • 低空经济与新能源催生央国企新岗位
  • CSDN Markdown自动发布踩坑记录与解决方案
  • AI时代为何第一刀就砍了程序员?
  • 无人机多光谱-生态三维建模全流程实战——基于Python与AI辅助技术
  • 2026年充电桩加盟品牌推荐:城市公共场站投资靠谱选择与运营避坑指南 - 品牌推荐
  • 2026年绩效管理咨询公司推荐:企业战略落地与组织效能提升靠谱选择指南 - 品牌推荐
  • HCTF2018 the_end
  • 2025-2026年充电桩加盟品牌推荐:光储充一体化解决方案口碑品牌盘点 - 品牌推荐
  • 亲测好用 9个降AIGC平台全场景通用测评,哪个最能帮你降AI率?
  • OpenClaw进阶实战:多智能体协同+自定义Skill开发,打造专属AI团队
  • 弃国外开源,创自主开源 Perseus:乐维的底层技术抉择与智能体战略
  • 告别AI Agent记忆混乱与幻觉!收藏这份RAG实战指南,小白也能轻松搞定大模型落地
  • Win11右键--新建文件名修改
  • 【统计检验】正态性检验
  • 激光雷达作物样例数据
  • AI 时代,前端先死,还是后端先死?
  • 2026.3.21 B. Twin Works
  • 面试必问的自动化测试框架你真会了吗?
  • springboot 项目集成 seate 分布式事务AT模式使用nacos完整配置步骤及说明
  • 南京租打印机别踩坑!押金透明、退机不扯皮才是王道
  • 0 基础入门 Agent:理论知识体系搭建指南
  • 【Kotlin】快速理解协程
  • 如何重置idea ai assistant ACP 插件中的 Cursor 账号登录状态?
  • 2026年3月拓竹H2C分析,拓竹多色打印系统受市场青睐,市面上诚信的拓竹多色打印系统公司分析综合实力与口碑权威评选 - 品牌推荐师
  • 机械行业文档系统如何解决CAD图纸跨平台粘贴?
  • 【统计分析】皮尔逊相关系数检验
  • 从 Token 到 Agent:一文串起 AI 大模型核心概念