什么是 ICMP 协议

关于这点我们在 IP 协议那篇文章中提过一嘴,IP 协议作为一种提供不可靠数据交付的网络层协议,在传输的过程中,其 IP 数据报可能会发生丢失、重复、延迟和乱序等各种情况, 但是 IP 协议对这些糟糕的情况并不拥有有效的检测和弥补措施,当然更不会将这些结果通知收发双方。

为此,鉴于上述原因,我们在构建 IP 网络时,就需要特别注意两点:

  • 确认网络是否能够正常工作
  • 即使诊断出现异常时的原因所在

于是,网际控制报文协议(Internet Control Message Protocol,ICMP)出现了。

形象来说,IP 协议就好像一个将军,而 ICMP 协议就是他手下的情报员。将军运筹帷幄于千里之外,而在前线浴血奋战的士卒们伤亡当然也在所难免。

那无法亲临前线的将军最起码要知道两件事情:第一点,我的士卒们是不是按照我指引的方向在前进着,别一阵猛冲发现冲错了地方;第二点,我的士卒们伤亡多少,被什么所伤,了解了己方伤亡的原因才好做下一步的战略部署,总不能死了个不明白。不必多说,这就是情报员 ICMP 该做的事情了。

当然了,上述只是打个比方,可能不是很严谨,各位知道什么意思就行,不必过于吹毛求疵。

这里我们再用学术点的语言来总结下,ICMP 的主要功能有如下两点:

1)确认 IP 数据报是否成功送达目标地址

2)如果某个 IP 数据报因为某种原因未能正常到达目的地,则由 ICMP 负责通知具体的原因

ICMP 报文初探

具体的出错原因是 ICMP 协议负责通知的,这个通知的学名就是 ICMP 报文,那么 ICMP 报文是由发送方发送方发出的还是由接收方发出的呢?

都不是。

ICMP 报文是由路由器发出来的

举个例子:主机 A 在不知情的情况下向主机 B 发送了数据包,而主机 B 正在呼呼大睡。主机 A 和主机 B 不在同一个局部网内,假设它俩之间会经过两个路由器,看下图:

众所周知,除了 IP 地址我们还需要 MAC 地址才能确保数据包精准的找到传送方向,因此,路由器 2 为了知道主机 B 的 MAC 地址,它会广播一个 ARP 请求报文,希望获取到主机 B 的 MAC 地址,而主机 B 都关机了自然也就无法应答这个请求报文了。

为此,路由器 2 会一遍又一遍的重新发送着 ARP 请求报文,在多次无果后,路由器 2 就会返回一个 ICMP Destination Unreachable 的包给主机 A(关于 ICMP 报文类型下文会讲),通知主机 A,非常遗憾,您发往主机 B 的包未能成功抵达。

那么,ICMP 报文具体是怎么传输给主机 A 的呢

这个很简单,TCP/UDP 报文是怎么传输的,ICMP 报文就怎么传输。

也就是说,真正的数据首先会被加上 ICMP 首部,封装成 ICMP 报文,然后被 IP 协议封装成 IP 数据报进行明文传输,由 IP 协议指定源 IP 地址和目的地址。主机 A 收到数据后会一层一层解封装,从而获得真正的数据得知发生异常的原因,遂大怒一声:蠢货主机 B。

ICMP 报文格式

至此,各位已经知道了,ICMP 报文是被封装在 IP 数据报里面的,我们来看看下图:

额,这里好像没啥好说的,上图画的很 Nice ,是我之前考研的时候看 B 站上的王道视频截下来的,各位看明白上图,了解 ICMP 报头有哪些东西,知道类型代码这两个字段很重要就好了,尤其是类型这个,接下来我们先重点讲它。

ICMP 报文类型

上文提到了 ICMP Destination Unreachable,也就是目标不可达的 ICMP 报文。

ICMP 报文类型大体上可以分为两种,差错报文和询问报文,解释一下:

所谓查询报文就是,用于主机进行诊断的查询消息

这么学术性的文字可能不是很好理解,这样,咱形象来说,查询报文其实和通信异常没啥关系,查询报文就好比将军率领着千军万马来到了一片寂静的峡谷,正是一个容易被埋伏的地方,将军不敢贸然前进,于是派遣几个情报员前去探明敌情,一有动静立马回报。

常见的 ICMP 查询报文类型有以下几种:

  • 回送应答(Echo Reply),对应 ICMP 报文首部类型字段的值:0
  • 回送请求(Echo Request),对应 ICMP 报文首部类型字段的值:8

而差错报文就是,用于通知主机出错的原因。显然,ICMP 差错报告报文是伴随着出错数据产生的。一旦 IP 协议发现某个 IP 数据报出错了,首先就会毅然地丢弃出错的这个 IP 数据报,然后发送 ICMP 差错报文

常见的 ICMP 差错报文类型有以下几种:

  • 目标不可达(Destination Unreachable),对应 ICMP 报文首部类型字段的值:3
  • 原点抑制(Source Quench),对应 ICMP 报文首部类型字段的值:4
  • 重定向或改变路由(Redirect),对应 ICMP 报文首部类型字段的值:5
  • 超时(Time Exceeded),对应 ICMP 报文首部类型字段的值:11

下面详细解释一下这几个常见的 ICMP 报文类型。

ICMP 回送消息(类型 0、8)

用于进行通信的主机或路由器之间,判断所发送的数据包是否已经成功到达对端的一种消息。

可以向对端主机发送 ICMP 回送请求的消息(Echo Request,类型 8),也可以接收对端主机发回来的 ICMP 回送应答消息(Echo Reply,类型 0)

我们常用的 ping 命令就是基于 ICMP 回送消息实现的。

ping 这个单词源自声纳定位,而这个命令的作用也确实如此,它发送类型为 0 的 ICMP Echo Request 消息,收到请求的主机则用类型为 8 的 ICMP Echo Reply 消息进行回应。ping 就会计算发送 Requenst 和接收到 Reply 的消息间隔时间,并计算有多少个包被送达,丢失了多少个包等。用户就可以据此判断网络大致的情况。

如下图我们来 ping 一下 Github:

ping 也并不是啥事也没做,它在 ICMP 报文格式中又添加了两个字段:标识符和序号。这俩其实很好理解:

1)标识符用来区分是哪个应用程序发 ICMP 包。

形象来说,将军派出了两个情报员,一个用来是了解战况的,一个是用来搬救兵的,那总得有个标识区分这俩情报员吧。标识符就是干这事的。最容易想到的能作为标识符的东西,想来也不用我多嘴吧,就是进程的 PID。

2)序号用来确认网络包是否有丢失。

形象来说,将军派出了 10 个情报员,给每个情报员都编个号。这样,如果派出去 10 个,回来 10 个,就说明前方战况不错;如果派出去 10 个,一个也没回来或者就回来 1 个,说明情况不妙啊。

ICMP 目标不可达消息(类型 3)

路由器无法将 IP 数据报发送给目标地址时,会给发送端主机返回一个目标不可达(Destination Unreachable Message)的 ICMP 消息。

那目标不可达有多种可能的原因,比如说网络问题、目标主机问题等等,所以这个目标不可达消息还需要指明不可达的具体原因,这个具体原因就记录在 ICMP 报头的代码字段。

那么这里我们仍然以行军打战的例子来看看常见的目标不可达类型的代码有哪些:

1)前方战事吃紧,将军(主机 A)派了一队士兵回京城找皇上(主机 B)搬救兵,中途情报员快马加鞭赶到汇报:将军,我们在途中迷失了方向,找不到京城在哪。这就是网络不可达,其代码为 0

2)假设士兵们成功回到京城,但是皇上出城了,不在京城,朝廷百官也不敢私自同意出兵救援。这就是主机不可达,到了地方却没找到人,其代码为 1

3)假设士兵成功找到了京城,但是由于将士们常年在外征战,守城的年轻护卫们已经不认识这些威名赫赫的将士们了,所以需要进城口令证明身份,但是久经沙场的将士们一时半会想不起来这些东西,遂无法进城。这就是协议不可达,其代码为 2

4)假设士兵们成功进了城,也成功面见了圣上,但是皇上却说密侦司告诉他的情报和你们说的不一样,你们说你们需要的是救兵,而我得到的消息是你们只需要粮草。这就是端口不可达,其代码为 3

5)假设士兵们成功求得了救兵,并且获得了火器十余箱,但是中途山路狭窄,装火器的马车太大过不去,为此需要换小一点的马车,每个马车装一点,但是由于火器技术尚不成熟,考虑安全问题,将军早就严令禁止把火器分装。于是乎,浩浩荡荡的援兵阻塞在了狭窄的山路。这就是需要进行分片但设置了不分片位,其代码为 4

ICMP 重定向消息(类型 5)

说到这个,我们先要明白 IP 协议或者网络层的职责是什么,就是选择合适的网间路由和交换结点, 确保数据的及时传送。

为此,我们总是倾向于基于最短最优的路径进行传输。

那么如果路由器发现发送端主机使用了某个不是最优的路径发送数据,他就会返回一个 ICMP 重定向消息(ICMP Redirect Message)给这个主机,并且,在这个消息中包含了最优的路由信息和源数据。

写上瘾了哈哈,举个例子:将军得知 ICMP 的情报后震怒,派出去搬救兵的领队竟然带着十万救兵在绕弯子,乱臣贼子,将军赶紧下令诛杀这个领队并立即走最近的路赶回来。

ICMP 超时消息(类型 11)

IP 包中有一个字段叫做 TTLTime To Live,生存周期),它的值随着每经过一次路由器就会减 1,直到减到 0 时该 IP 包会被丢弃

此时,IP 路由器将会发送一个 ICMP 超时消息(ICMP Time Exceeded Message)给发送端主机,并通知该包已被丢弃。

形象来说,就是将军派出去的搬救兵的那队人马苦于找不到京城的方向,路途开始带上的只够三天的粮草断尽,全队饮恨而死。

设置 IP 包生存周期的主要目的,是为了在路由控制遇到问题发生循环状况时,避免 IP 包无休止地在网络上被转发。

ICMP 的应用

其中一个应用 ping 命令我们已经说过了,它是基于 ICMP 查询报文的。

还有一个命令,是基于 ICMP 差错报文的,在 Linux 下这条命令是 traceroute,在 Windows 是 tracert

大家可能会觉得 ICMP 差错报文是只有在通信异常的时候才会生成,其实不然,traceroute 命令就是一个例外,它会使用 ICMP 的规则,故意制造一些能够产生异常的场景。

traceroute 命令有两大作用:

1)故意设置特殊的 TTL,来追踪去往目的主机上沿途经过的路由器

具体来说,就是发送端主机会不断的向接收端主机发送 UDP 报文,UDP 报文被封装成 IP 数据报,同时将 TTL 从 1 开始按照顺序递增。

比如说,将 TTL 设置 为 1,那么遇到第一个路由器的时候,这个 IP 数据报就会被丢弃,接着返回 ICMP 差错报文,类型是 ICMP 超时消息

接下来将 TTL 设置为 2,第一个路由器过了,遇到第二个路由器时这个 IP 数据报就会被丢弃,接着返回ICMP 差错报文。

......

这样,traceroute 就拿到了所有路由器 IP。

那到这里其实还有一个问题,怎么知道数据到底有没有到达目的主机呢

traceroute 是基于 UDP 传输的,那自然是需要指定一个端口号的,traceroute 会选择一个不可能的值作为 UDP 的端口号。

这样,当数据到达目的主机时,就会发现端口对不上,于是路由器会产生一份 ICMP 目标不可达消息,其代码是 3,即端口不可达

当发送端主机接收这份端口不可达的 ICMP 报文时,就知道目的主机成功收到了数据。

2)故意设置不分片,从而确定路径的最大传输单元 MTU

某些情况下我们并不知道路径的 MTU 大小,所以我们需要某种手段去获取 MTU,才能控制发送的数据包的大小。

发送端主机要做的工作很简单,就是像往常一样发送 IP 数据报,但是将 IP 首部的分片禁止标志位置为 1。

这样,如果 IP 数据报的长度超过了 MTU,该数据报会被路由器直接丢弃,并且给发送端主机发送 ICMP 目标不可达消息,其代码为 4,即需要进行分片但设置了不分片位

这样,发送端主机每次收到 ICMP 需要进行分片但设置了不分片位消息时就减小 IP 数据报的长度,直到顺利到达目标主机。

关注公众号 | 飞天小牛肉,即时获取更新

  • 博主东南大学硕士在读,携程 Java 后台开发暑期实习生,利用课余时间运营一个公众号『 飞天小牛肉 』,2020/12/29 日开通,专注分享计算机基础(数据结构 + 算法 + 计算机网络 + 数据库 + 操作系统 + Linux)、Java 技术栈等相关原创技术好文。本公众号的目的就是让大家可以快速掌握重点知识,有的放矢。关注公众号第一时间获取文章更新,成长的路上我们一起进步
  • 并推荐个人维护的开源教程类项目: CS-Wiki(Gitee 推荐项目,现已累计 1.6k+ star), 致力打造完善的后端知识体系,在技术的路上少走弯路,欢迎各位小伙伴前来交流学习 ~
  • 如果各位小伙伴春招秋招没有拿得出手的项目的话,可以参考我写的一个项目「开源社区系统 Echo」Gitee 官方推荐项目,目前已累计 700+ star,基于 SpringBoot + MyBatis + MySQL + Redis + Kafka + Elasticsearch + Spring Security + ... 并提供详细的开发文档和配套教程。公众号后台回复 Echo 可以获取配套教程,目前尚在更新中。

所谓 ICMP,不过将军与士卒而已的更多相关文章

  1. DHCP:IP 并非与生俱来

    初识 DHCP 众所周知,因特网上的每台设备都规定了其全世界唯一的地址,也就是说 "IP 地址",正是由于有了 IP 地址,才保证了用户在连网的计算机上操作时,能够高效而且方便地从 ...

  2. 网络协议 5 - ICMP 与 ping:投石问路的侦察兵

        日常开发中,我们经常会碰到查询网络是否畅通以及域名对应 IP 地址等小需求,这时候用的最多的应该就是 ping 命令了. 那你知道 ping 命令是怎么工作的吗?今天,我们就来一起认识下 pi ...

  3. 网络协议 5 - ICMP 与 Ping

    日常开发中,我们经常会碰到查询网络是否畅通以及域名对应 IP 地址等小需求,这时候用的最多的应该就是 ping 命令了. 那你知道 ping 命令是怎么工作的吗?今天,我们就来一起认识下 ping 命 ...

  4. 7(计算机网络) ICMP与ping

    无论是在宿舍,还是在办公室,或者运维一个数据中心,我们常常会遇到网络不通的问题.那台机器明明就在那里,你甚至都可以通过机器的终端连上去看.它看着好好的,可是就是连不上去,究竟是哪里出了问题呢? ICM ...

  5. 网络协议学习笔记(二)物理层到MAC层,交换机和VLAN,ICMP与ping原理

    概述 之前网络学习笔记主要讲解了IP的诞生,或者说整个操作系统的诞生,一旦有了IP,就可以在网络的环境里和其他的机器展开沟通了.现在开始给大家讲解关于网络底层的相关知识. 从物理层到MAC层:如何在宿 ...

  6. [协议]ICMP协议剖析

    1.ICMP简介 ICMP全名为(INTERNET CONTROL MESSAGE PROTOCOL)网络控制消息协议. ICMP的协议号为1. ICMP报文就像是IP报文的小弟,总顶着IP报文的名头 ...

  7. 简单了解ICMP协议

    ping命令是什么协议? 维基百科: ping是一种电脑网络工具,用来测试数据包能否通过IP协议到达特定主机.ping的运作原理是向目标主机传出一个ICMP echo@要求数据包,并等待接受echo回 ...

  8. ICMP的应用--Traceroute

    Traceroute是用来侦测主机到目的主机之间所经路由情况的重要工具,也是最便利的工具.前面说到,尽管ping工具也可以进行侦测,但是,因为ip头的限制,ping不能完全的记录下所经过的路由器.所以 ...

  9. ICMP Protocol

    [ICMP Protocol] 参考: 1.ICMP Types and Codes:http://www.nthelp.com/icmp.html 2.RFC 792 - Internet Cont ...

随机推荐

  1. 如何创建一个Maven项目(eclipse版本)

    1 Maven概念 Maven是一个构建项目和管理项目依赖的工具 2 Maven运行原理 这里需要引入两个词汇,叫 本地仓库.中央仓库 本地仓库:就字面意思,存储在自己电脑上的文件夹(需要自己手动创建 ...

  2. WPF -- 构建动画

    写在前面:本文代码摘自<Head First C#> 本文使用ObjectAnimationUsingKeyFrames + Storyboard构建一个动画. ObjectAnimati ...

  3. ElasticSearch 集群的规划部署与运维

    公号:码农充电站pro 主页:https://codeshellme.github.io 1,常见的集群部署方式 ES 有以下不同类型的节点: Master(eligible)节点:只有 Master ...

  4. mysql查询较长的执行进程及创建权限账号

    A:对于死锁,进程的操作 1.查找当前活跃事务 SELECT * from information_schema.INNODB_TRX 根据trx_started等判断事务是否异常锁定 2.杀死线程 ...

  5. 【odoo】ref 1-6说明

    (0,_ ,{'field': value}) 这将创建一个新的记录并连接它          (1,id,{'field': value}): 这是更新一个已经连接了的记录的值          ( ...

  6. 微服务分布式事务之LCN、TCC

    在亿级流量架构之分布式事务解决方案对比中, 已经简单阐明了从本机事务到分布式事务的演变过程, 文章的最后简单说明了TCC事务, 这儿将会深入了解TCC事务是原理, 以及理论支持, 最后会用Demo举例 ...

  7. ACM常用的C++ && STL

    内容 c++输入输出 c++ string vector:不定长数组 map:映射 queue:队列 sort:排序 priority_queue:优先队列 c++输入输出 1 #include &l ...

  8. Flask面试问题

    1,什么是Flask,有什么优点?概念解释Flask是一个Web框架,就是提供一个工具,库和技术来允许你构建一个Web应用程序.这个Web应用程序可以是一些Web页面,博客,wiki,基于Web的日里 ...

  9. 史上超强拷贝仓——GitHub 热点速览 v.21.11

    作者:HelloGitHub-小鱼干 Clone-Wars 是真的强,能细数 70+ 知名应用网站的源码,即便你不看代码,也可以了解下各大网站的所用技术栈.同样很强的是用 OpenCV 实现的图片转 ...

  10. C# 8 中的异步迭代器 IAsyncEnumerable<T> 解析

    异步编程已经流行很多年了,.NET 引入的 async 和 await 关键词让异步编程更具有可读性,但有一个遗憾,在 C# 8 之前都不能使用异步的方式处理数据流,直到 C# 8 引入的 IAsyn ...