大家好,我是风筝
轻解网络系列又来了。已有高清 PDF 版本可以离线阅读了,全册 65 页,如果有需要离线版的高清 PDF 可以直接下载。
今天咱们说说 ICMP 协议。ICMP 可谓是网络世界中的最强辅助了,IP数据包如果在途中遭遇不测的话,全靠 ICMP 来通知,要不然丢掉的IP数据包就有如石沉大海,从此杳无音信,发送方也不知道这个包有没有传输成功,倘若没有成功,那失败原因是什么?这些,全靠 ICMP 协议来通知。
ICMP 全称互联网控制报文协议(Internet Cntrol Message Protocol),是网络层的重要协议。
ICMP 是干啥用的
它到底是用来干啥的呢?为啥叫控制报文协议,控制的是什么?
ICMP 分为查询报文和差错报文两大类。查询报文是我们主动发起的,比如ping命令;而差错报文是在发生差错之后要发给源端的,这都是互联网协议模型约定好的。
ICMP的差错报文反馈发生在通信环境中的遇到的各种问题。通过这些信息,使管理者可以对所发生的问题作出诊断,然后采取适当的措施解决。
ICMP的差错报文是整个数据传输链路中非常重要的一个环节。打个比喻,差错报文就是一个只报告坏消息的信使,当数据包在网络中一路畅通的时候,ICMP 差错报文就像隐身了一样,你根本不会知道它的存在,一旦数据包在网络中碰到了各种各样的障碍,这个信使就出来活动了,它的目的只有一个,就是把这个数据包遭遇的不测通知给发送端,但是话术就那么20多种(对应差错代码)。
比如下面两个场景,想必你也有点熟悉吧。
-
当路由器收到一份IP数据报但又不能转发时,就要发送一份 ICMP「主机不可达」差错报文。
-
当IP数据报应该被发送到另一个路由器时,收到数据报的路由器就要发送 ICMP「重定向」差错报文给IP数据报的发送端。
ICMP 协议说明
虽然工作在网络层,看上去和 IP 协议是并列的,但是 ICMP 报文要附加 IP 头,一般被 IP 层或者更高层的协议(例如TCP或UDP)使用。很少有应用程序直接使用 ICMP 协议,除了 ping
、traceroute
。
ICMP 协议格式
ICMP 协议格式和 IP 协议、TCP 协议这些比起来,那还是非常简单的。
类型
类型字段占用 8 位,主要定义报文的大类,比如类型为 3 统一表示的是不可达
,而具体原因是什么则要由代码字段决定。
代码
代码字段同样占用 8 位,代码字段其实就是类型下的子类型,比如上面说了类型为 3 是不可达,代码为 0 表示网络不可达,代码为 1 表示主机不可达。
检验和
用于错误检查,和 IP 协议的检验和的作用一致。
内容
因为类型和代码不同,表示产生差错的原因不同,不同的原因都要有对应的描述,内容这部分就是用来描述产生差错的原因的。
接下来会举几个例子说明。
下面这张图是 ICMP 的分类,包括查询报文和差错报文,需要原始 Excel 的同学可以回复 ICMP
获取源文件。
目的不可达差错报文
目的不可达是网络传输中经常遇到的问题,各位在开发的过程中可能也碰到过,尤其是做网络编程的时候,经常会碰到,比如连错IP了,比如端口设置错了。
通过上表可知,当类型为 3 的时候,都是不可达的错误,而代码可以从 0 -15,也就是说有16种不可达的具体原因。这种情况下的协议格式是下面这样的。
类型为 3 ,代码 0 - 15。检验和后面有 4 个字节的空间是不使用的,但是必须为0 ,没理由,就这样。
前面说到了内容部分是根据类型和代码不同而不同的。如果是目的不可达,也就是类型是 3 的情况下,内容分为两部分,IP首部和原始IP数据报中数据部分的前 8 个字节。
原始IP数据报中数据部分指的就是TCP或者UDP这些网络层之上的协议,拿 TCP 来说,TCP 是传输层的,当 TCP 数据报到达网络层,会加上 IP 首部,变成一个 IP 数据包。所以这里说的数据部分就是 TCP 数据报,但是这个数据报可能很大,所以只用前 8 个字节就够了,因为前8个字节包含的信息已经足够用了。
回想一下 TCP 协议的格式,前 8 个字节就是下图红框部分,包含源端口和目的端口以及序号。
例如代码为 3 的时候,差错信息是端口不可达,那有了 TCP 协议的前8个字节就能知道导致这个错误的原始数据报文中的目的端口是多少,不可达的端口也就是这个端口。也可以知道原始报文的源端口是多少,有了源端口号就知道这个数据包是哪个用户进程发出来的,就可以交给这个进程对这个差错及时进行处理了。
源端口号是关联用户进程的重要标示,比如我们开发了一个应用,这个应用占用了 8888和8898两个端口,如果安装了这个应用的机器收到了一个差错报文,而差错报文中的内容部分的原始数据包前8个字节拆解后,发现源端口是8898,那就知道这个要交给我们开发的这个应用去处理了。
下面是一个端口不可达的差错报文,用 WireSharek 监测到的格式。
telnet 一个没有开放的端口即可获得 ICMP 端口不可达的差错报文。
查询报文
将 ICMP 用作查询报文的场景比较少,用作查询报文的意思就像是使用 ARP 协议或者 TCP 协议这种,是我们主动发起的,只不过选了 ICMP 协议。
比如 ping
和 traceroute
这两个,之后我们再讲,这两个比较有意思,对 ICMP 应用很巧妙。
另外,可以用作无盘系统启动过程中来获取自身的子网掩码。还可以用作向第三方系统查询当前的时间戳。
了解一下就可以了。
有一些场景不发送差错报文
有些场景下是不发送差错报文的,这样做的目的是为了防止ICMP差错报文带来广播风暴。
-
ICMP差错报文本身发生差错,是不会对差错报文再发送差错报文的。是不是读起来有点绕,TCP 、UDP 出错会发送差错报文,但是 ICMP差错报文在通知源端的过程出错了,那就不管了,要不然可能就没玩没了的发了,比如源端的网线断了。但是, ICMP查询报文可能会产生ICMP差错报文,比如ping命令在传输过程中出错了,源端会收到差错报文。
-
目的地址是广播地址或多播地址(D类地址)的IP数据报,不发送差错报文。
-
作为链路层广播的数据报,不发送差错报文,ARP 就是典型的链路层广播数据报。
-
不是IP分片的第一片,不发送差错报文。数据如果过长,网络层是会进行分片的,这些分片实际上还是同一个数据包的,这种情况下只对第一片发送差错报文,其他分片不管。
-
源地址不是单个主机的数据报,不发送差错报文。 源地址不能为零地址、环回地址、广播地址或多播地址。
总结
1、 ICMP 在网络层,但要加上 IP 首部;
2、ICMP 分为查询报文和差错报文,主要用到的还是差错报文;
3、ICMP 的差错报文就好像一个只通知坏消息的信息,当数据报在网络中出现问题的时候,及时告知源端,告知的内容包括原因以及产生错误的原始数据报的必要部分;
4、有一些情况是不会发送 ICMP 差错报文的,这样做是为了防止网络风暴;
如果觉得还不错的话,给个推荐吧!
公众号「古时的风筝」,Java 开发者,专注 Java 及周边生态。坚持原创干货输出,你可选择现在就关注我,或者看看历史文章再关注也不迟。长按二维码关注,跟我一起变优秀!