简单理解:ICMP 是什么?

发布时间:2026/5/24 20:37:18

简单理解:ICMP 是什么? 1.ICMP Internet Control Message Protocol互联网控制报文协议一句话它不是用来传用户数据的是用来给 IP 网络 “报信、报错、检测” 的。2. 最常见的用途1Ping 命令你平时用的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 联网STM32LAN8720、ESP32想实现ping 功能就要开 ICMPLwIP 协议栈里默认就带 ICMP一般不用自己写超简总结ICMP 网络的 “诊断 报错” 协议最典型代表ping不和你发数据只告诉你通不通、哪断了、超时了。LwIP 是嵌入式领域最常用的轻量级 TCP/IP 协议栈其 ICMP 实现核心代码集中在icmp.c/icmp.h文件中我会提取核心关键代码基于 LwIP 2.1.2 版本最稳定的主流版本并逐行解释关键逻辑适配 STM32 等嵌入式场景一、先明确核心文件与功能文件核心作用src/core/icmp.cICMP 报文的接收、解析、响应如 Pingsrc/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.cicmp_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_ECHO8-------------- */ 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. 被动 PingSTM32 被电脑 Ping流程2. 主动 PingSTM32 Ping 网关流程// STM32代码示例主动Ping网关192.168.1.1 ip_addr_t gw_addr; IP4_ADDR(gw_addr, 192, 168, 1, 1); // 发送Ping请求ID0x1234序列号1TTL64 icmp_send_echo(gw_addr, 0x1234, 1, 64);四、嵌入式适配关键注意事项pbuf 内存管理LwIP 中pbuf_alloc是核心STM32 需配置内存池大小MEM_SIZE避免 Ping 包分配失败校验和优化STM32 以太网外设如 LAN8720支持硬件校验和开启LWIP_CHECKSUM_ON_COPY可减少 CPU 占用中断 / 线程配合ICMP 处理建议放在 LwIP 的tcpip_thread线程中默认如此避免在中断中直接处理资源限制嵌入式中关闭不必要的 ICMP 类型如目标不可达、超时仅保留ICMP_ECHO/ICMP_ER节省内存。总结核心关键点LwIP 的 ICMP 核心是icmp_input处理接收和icmp_send_echo处理发送Ping 响应的核心逻辑解析请求→修改类型→重算校验和→交换 IP→发送应答STM32 中只需开启LWIP_ICMP1无需修改核心代码即可实现 Ping 功能嵌入式场景下重点关注pbuf内存分配和硬件校验和优化保证 Ping 响应稳定。

相关新闻