IP 全家桶
IP 基本认识
IP 属于网络层,负责的是主机与主机之间的通信
网络层与数据链路层有什么关系呢?
MAC 的作用则是实现「直连」的两个设备之间通信,而 IP 则负责在「没有直连」的两个网络之间进行通信传输。
在网络中数据包传输中也是如此,源 IP 地址和目标 IP 地址在传输过程中是不会变化的(前提:没有使用 NAT 网络),只有源 MAC 地址和目标 MAC 一直在变化。
IP 地址
IP 地址(IPv4 地址)由 32
位正整数来表示,IP 地址在计算机是以二进制的方式处理的。
人类为了方便记忆采用了点分十进制的标记方式,也就是将 32 位 IP 地址以每 8 位为组,共分为 4
组,每组以「.
」隔开,再将每组转换成十进制。
所以 IP 地址是由最大值的,2^32 = 43 亿左右;即最多 43 亿个设备连接到网络
IP 地址是以网卡配置 IP。像服务器、路由器等设备都是有 2 个以上的网卡,也就是它们会有 2 个以上的 IP 地址。有限的 IP 匹配更多的设备就需要 NAT 技术
IP 地址的分类
共有 5 类 IP
最大主机个数 = 2 ^ 主机号位数 - 2
主机号全 0 和全 1 的两个 IP 地址是有特殊作用的,不能给主机当 IP
- 主机号全为 1 指定某个网络下的所有主机,用于广播
- 主机号全为 0 指定某个网络
广播的知识
广播地址用于在同一个链路中相互连接的主机之间发送数据包。
- 在本网络内广播的叫做本地广播。例如网络地址为 192.168.0.0/24 的情况下,广播地址是 192.168.0.255 。因为这个广播地址的 IP 包会被路由器屏蔽,所以不会到达 192.168.0.0/24 以外的其他链路上。
- 在不同网络之间的广播叫做直接广播。例如网络地址为 192.168.0.0/24 的主机向 192.168.1.255/24 的目标地址发送 IP 包。收到这个包的路由器,将数据转发给 192.168.1.0/24,从而使得所有 192.168.1.1~192.168.1.254 的主机都能收到这个包(由于直接广播有一定的安全问题,多数情况下会在路由器上设置为不转发。) 。
D,E 类 IP 地址
D 类和 E 类地址是没有主机号的,所以不可用于主机 IP,D 类常被用于多播,E 类是预留的分类,暂时未使用。
多播地址用于什么?
多播用于将包发送给特定组内的所有主机。由于广播无法穿透路由,若想给其他网段发送同样的包,就可以使用可以穿透路由的多播。
IP 地址分类优点和缺点
判断 IP 地址属于哪一类的方式:
IP 分类的缺点
缺点一
同一网络下没有地址层次,比如一个公司里用了 B 类地址,但是可能需要根据生产环境、测试环境、开发环境来划分地址层次,而这种 IP 分类是没有地址层次划分的功能,所以这就缺少地址的灵活性。
缺点二
A、B、C 类有个尴尬处境,就是不能很好的与现实网络匹配。
- C 类地址能包含的最大主机数量实在太少了,只有 254 个,估计一个网吧都不够用。
- 而 B 类地址能包含的最大主机数量又太多了,6 万多台机器放在一个网络下面,一般的企业基本达不到这个规模,闲着的地址就是浪费。
为了应对这两个缺点,使用了 CIDR(无分类地址)
CIDR
实现:32 比特的 IP 地址被划分为两部分,前面是网络号,后面是主机号。表示形式 a.b.c.d/x
,其中 /x
表示前 x 位属于网络号, x 的范围是 0 ~ 32
,这就使得 IP 地址更加具有灵活性。
为什么要分离网络号和主机号?
因为两台计算机要通讯,首先要判断是否处于同一个广播域内,即网络地址是否相同。如果网络地址相同,表明接受方在本网络上,那么可以把数据包直接发送到目标主机。
路由器寻址工作中,也就是通过这样的方式来找到对应的网络号的,进而把数据包转发给对应的网络内。
怎么进行子网划分?
通过子网掩码划分出网络号和主机号,实际上子网掩码还有一个作用,那就是划分子网。
子网划分实际上是将主机地址分为两个部分:子网网络地址和子网主机地址。形式如下:
- 未做子网划分的 ip 地址:网络地址+主机地址
- 做子网划分后的 ip 地址:网络地址+(子网网络地址+子网主机地址)
假设对 C 类地址进行子网划分,网络地址 192.168.1.0,使用子网掩码 255.255.255.192 对其进行子网划分。
C 类地址中前 24 位是网络号,最后 8 位是主机号,根据子网掩码可知从 8 位主机号中借用 2 位作为子网号。
由于子网网络地址被划分成 2 位,那么子网地址就有 4 个,分别是 00、01、10、11
公有 IP 地址与私有 IP 地址
A,B,C 类 IP 地址才有公私 IP 之分
平时办公室、家里、学校用的 IP 地址,一般都是私有 IP 地址。因为这些地址允许组织内部的 IT 人员自己管理、自己分配,而且可以重复。
公有 IP 地址是由ICANN
统一分配的,假设要开一个博客网站,那么就需要去申请购买一个公有 IP,这样全世界的人才能访问。并且公有 IP 地址基本上要在整个互联网范围内保持唯一。
IP 地址与路由控制
IP 地址的网络地址这一部分是用于进行路由控制。
路由控制表中记录着网络地址与下一步应该发送至路由器的地址。在主机和路由器上都会有各自的路由器控制表。
在发送 IP 包时,首先要确定 IP 包首部中的目标地址,再从路由控制表中找到与该地址具有相同网络地址的记录,根据该记录将 IP 包转发给相应的下一个路由器。如果路由控制表中存在多条相同网络地址的记录,就选择相同位数最多的网络地址,也就是最长匹配。
环回地址不会流向网络
环回地址是在同一台计算机上的程序之间进行网络通信时所使用的一个默认地址。
计算机使用一个特殊的 IP 地址 127.0.0.1 作为环回地址。与该地址具有相同意义的是一个叫做 localhost
的主机名。使用这个 IP 或主机名时,数据包不会流向网络。
IP 分片与重组
每种数据链路的最大传输单元 MTU
都是不相同的,如 FDDI 数据链路 MTU 4352、以太网的 MTU 是 1500 字节等。
那么当 IP 数据包大小大于 MTU 时, IP 数据包就会被分片。
经过分片之后的 IP 数据报在被重组的时候,只能由目标主机进行,路由器是不会进行重组的。
假设发送方发送一个 4000 字节的大数据报,若要传输在以太网链路,则需要把数据报分片成 3 个小数据报进行传输,再交由接收方重组成大数据报。
在分片传输中,一旦某个分片丢失,则会造成整个 IP 数据报作废,所以 TCP 引入了 MSS
也就是在 TCP 层进行分片不由 IP 层分片,那么对于 UDP 我们尽量不要发送一个大于 MTU
的数据报文。
IPv6 基本认识
但是 IPv6 的地址是 128
位的,这可分配的地址数量是大的惊人,说个段子 IPv6 可以保证地球上的每粒沙子都能被分配到一个 IP 地址。
但是因为 IPv4 和 IPv6 不能相互兼容,所以不但要我们电脑、手机之类的设备支持,还需要网络运营商对现有的设备进行升级,所以这可能是 IPv6 普及率比较慢的一个原因。
IPv6 的亮点
- IPv6 可自动配置,即使没有 DHCP 服务器也可以实现自动分配 IP 地址,真是便捷到即插即用啊。
- IPv6 包头包首部长度采用固定的值
40
字节,去掉了包头校验和,简化了首部结构,减轻了路由器负荷,大大提高了传输的性能。 - IPv6 有应对伪造 IP 地址的网络安全功能以及防止线路窃听的功能,大大提升了安全性。
IPv6 地址的标识方法
IPv6 地址长度是 128 位,是以每 16 位作为一组,每组用冒号 「:」 隔开。
如果出现连续的 0 时还可以将这些 0 省略,并用两个冒号 「::」隔开。但是,一个 IP 地址中只允许出现一次两个连续的冒号。
IPv4 首部与 IPv6 首部
IPv6 相比 IPv4 的首部改进:
- 取消了首部校验和字段。 因为在数据链路层和传输层都会校验,因此 IPv6 直接取消了 IP 的校验。
- 取消了分片/重新组装相关字段。 分片与重组是耗时的过程,IPv6 不允许在中间路由器进行分片与重组,这种操作只能在源与目标主机,这将大大提高了路由器转发的速度。
- 取消选项字段。 选项字段不再是标准 IP 首部的一部分了,但它并没有消失,而是可能出现在 IPv6 首部中的「下一个首部」指出的位置上。删除该选项字段使的 IPv6 的首部成为固定长度的
40
字节。
ARP 协议
ARP 协议是用于根据 IP 地址确定 MAC 地址的协议,具体是借助 ARP 请求和 ARP 响应两种类型的包来确定 MAC 地址
- 主机会通过广播发送 ARP 请求,这个包中包含了想要知道的 MAC 地址的主机 IP 地址。
- 当同个链路中的所有设备收到 ARP 请求时,会去拆开 ARP 请求包里的内容,如果 ARP 请求包中的目标 IP 地址与自己的 IP 地址一致,那么这个设备就将自己的 MAC 地址塞入 ARP 响应包返回给主机
RARP 协议你知道是什么吗?
RARP 协议是已知 MAC 地址求 IP 地址。例如将打印机服务器等小型嵌入式设备接入到网络时就经常会用得到。
通常这需要架设一台 RARP
服务器,在这个服务器上注册设备的 MAC 地址及其 IP 地址。然后再将这个设备接入到网络,接着:
- 该设备会发送一条「我的 MAC 地址是 XXXX,请告诉我,我的 IP 地址应该是什么」的请求信息。
- RARP 服务器接到这个消息后返回「MAC 地址为 XXXX 的设备,IP 地址为 XXXX」的信息给这个设备。
最后,设备就根据从 RARP 服务器所收到的应答信息设置自己的 IP 地址。
DHCP
DHCP 协议用于动态获取 IP 地址,省去配置 IP 的繁琐过程
DHCP 客户端进程监听的是 68 端口号,DHCP 服务端进程监听的是 67 端口号。
- 客户端首先发起 DHCP 发现报文(DHCP DISCOVER) 的 IP 数据报,由于客户端没有 IP 地址,也不知道 DHCP 服务器的地址,所以使用的是 UDP 广播通信,其使用的广播目的地址是 255.255.255.255(端口 67) 并且使用 0.0.0.0(端口 68) 作为源 IP 地址。DHCP 客户端将该 IP 数据报传递给链路层,链路层然后将帧广播到所有的网络中设备。
- DHCP 服务器收到 DHCP 发现报文时,用 DHCP 提供报文(DHCP OFFER) 向客户端做出响应。该报文仍然使用 IP 广播地址 255.255.255.255,该报文信息携带服务器提供可租约的 IP 地址、子网掩码、默认网关、DNS 服务器以及 IP 地址租用期。
- 客户端收到一个或多个服务器的 DHCP 提供报文后,从中选择一个服务器,并向选中的服务器发送 DHCP 请求报文(DHCP REQUEST)进行响应,回显配置的参数。
- 最后,服务端用 DHCP ACK 报文对 DHCP 请求报文进行响应,应答所要求的参数。
咦,用的是广播,那如果 DHCP 服务器和客户端不是在同一个局域网内,路由器又不会转发广播包,那不是每个网络都要配一个 DHCP 服务器?
所以,为了解决这一问题,就出现了 DHCP 中继代理。有了 DHCP 中继代理以后,对不同网段的 IP 地址分配也可以由一个 DHCP 服务器统一进行管理。
- DHCP 客户端会向 DHCP 中继代理发送 DHCP 请求包,而 DHCP 中继代理在收到这个广播包以后,再以单播的形式发给 DHCP 服务器。
- 服务器端收到该包以后再向 DHCP 中继代理返回应答,并由 DHCP 中继代理将此包广播给 DHCP 客户端 。
NAT:网络地址转换
NAT 用于解决 IPv4 中 IP 地址不足的问题,解决思路是一个区域向外部区域进行通信时,将私有 IP 转换成公有 IP。(普通 NAT 思路)
由于绝大多数的网络应用采用 TCP/UDP 通信,所以可以把 IP 地址和端口号一起进行转换,这样一个区域的所有设备在外部看来就可以使用同一个 IP 地址,转而使用端口号进行区分区域内的设备(NAPT)。
这个 NAPT 路由表会在 NAT 路由器上自动生成和更新,比如区域内主机与服务器 TCP 通信时,三次握手时就在路由表上添加这条转换条目,四次挥手时就删除这个条目
NAT 那么牛逼,难道就没缺点了吗?
当然有缺陷,肯定没有十全十美的方案。
由于 NAT/NAPT 都依赖于自己的转换表,因此会有以下的问题:
- 外部无法主动与 NAT 内部服务器建立连接,因为 NAPT 转换表没有转换记录。
- 转换表的生成与转换操作都会产生性能开销。
- 通信过程中,如果 NAT 路由器重启了,所有的 TCP 连接都将被重置。
解决 NAT 的问题思路
- 改用 IPv6
- NAT 穿透技术:客户端主动从 NAT 设备获取公有 IP 地址,然后自己建立端口映射条目,然后用这个条目对外通信,就不需要 NAT 设备来进行转换了。
ICMP:互联网控制报文协议
ICMP
主要的功能包括:确认 IP 包是否成功送达目标地址、报告发送过程中 IP 包被废弃的原因和改善网络设置等。
在 IP
通信中如果某个 IP
包因为某种原因未能达到目标地址,那么这个具体的原因将由 ICMP 负责通知。
ICMP 类型
- 一类是用于诊断的查询消息,也就是「查询报文类型」
- 另一类是通知出错原因的错误消息,也就是「差错报文类型」
IGMP
在前面我们知道了组播地址,也就是 D 类地址,既然是组播,那就说明是只有一组的主机能收到数据包,不在一组的主机不能收到数组包,怎么管理是否是在一组呢?那么,就需要 IGMP
协议了。
IGMP 是因特网组管理协议,工作在主机(组播成员)和最后一跳路由之间,如上图中的蓝色部分。
- IGMP 报文向路由器申请加入和退出组播组,默认情况下路由器是不会转发组播包到连接中的主机,除非主机通过 IGMP 加入到组播组,主机申请加入到组播组时,路由器就会记录 IGMP 路由器表,路由器后续就会转发组播包到对应的主机了。
- IGMP 报文采用 IP 封装,IP 头部的协议号为 2,而且 TTL 字段值通常为 1,因为 IGMP 是工作在主机与连接的路由器之间。
IGMP 工作机制
常规查询与响应工作机制
- 路由器会周期性发送目的地址为
224.0.0.1
(表示同一网段内所有主机和路由器) IGMP 常规查询报文。 - 主机 1 和 主机 3 收到这个查询,随后会启动「报告延迟计时器」,计时器的时间是随机的,通常是 0~10 秒,计时器超时后主机就会发送 IGMP 成员关系报告报文(源 IP 地址为自己主机的 IP 地址,目的 IP 地址为组播地址)。如果在定时器超时之前,收到同一个组内的其他主机发送的成员关系报告报文,则自己不再发送,这样可以减少网络中多余的 IGMP 报文数量。
- 路由器收到主机的成员关系报文后,就会在 IGMP 路由表中加入该组播组,后续网络中一旦该组播地址的数据到达路由器,它会把数据包转发出去。
离开组播组工作机制
离开组播组的情况一,网段中仍有该组播组:
- 主机 1 要离开组 224.1.1.1,发送 IGMPv2 离组报文,报文的目的地址是 224.0.0.2(表示发向网段内的所有路由器)
- 路由器 收到该报文后,以 1 秒为间隔连续发送 IGMP 特定组查询报文(共计发送 2 个),以便确认该网络是否还有 224.1.1.1 组的其他成员。
- 主机 3 仍然是组 224.1.1.1 的成员,因此它立即响应这个特定组查询。路由器知道该网络中仍然存在该组播组的成员,于是继续向该网络转发 224.1.1.1 的组播数据包。
离开组播组的情况二,网段中没有该组播组:
- 主机 1 要离开组播组 224.1.1.1,发送 IGMP 离组报文。
- 路由器收到该报文后,以 1 秒为间隔连续发送 IGMP 特定组查询报文(共计发送 2 个)。此时在该网段内,组 224.1.1.1 已经没有其他成员了,因此没有主机响应这个查询。
- 一定时间后,路由器认为该网段中已经没有 224.1.1.1 组播组成员了,将不会再向这个网段转发该组播地址的数据包。
ping 工作原理:ping 是基于 ICMP
协议工作的
IP 协议的助手 —— ICMP 协议
ICMP 包头格式
ICMP 报文是封装在 IP 包里面,它工作在网络层,是 IP 协议的助手。
ICMP 包头的类型字段,大致可以分为两大类:
- 一类是用于诊断的查询消息,也就是「查询报文类型」
- 另一类是通知出错原因的错误消息,也就是「差错报文类型」
查询报文类型
回送消息 —— 类型
0
和8
回送消息用于进行通信的主机或路由器之间,判断所发送的数据包是否已经成功到达对端的一种消息,ping
命令就是利用这个消息实现的。
可以向对端主机发送回送请求的消息(ICMP Echo Request Message
,类型 8
),也可以接收对端主机发回来的回送应答消息(ICMP Echo Reply Message
,类型 0
)。
相比原生的 ICMP,这里多了两个字段:
- 标识符:用以区分是哪个应用程序发 ICMP 包,比如用进程
PID
作为标识符; - 序号:序列号从
0
开始,每发送一次新的回送请求就会加1
, 可以用来确认网络包是否有丢失。
在选项数据中,ping
还会存放发送请求的时间值,来计算往返时间,说明路程的长短。
差错报文类型
目标不可达消息(Destination Unreachable Message) —— 类型为
3
IP 路由器无法将 IP 数据包发送给目标地址时,会给发送端主机返回一个目标不可达的 ICMP 消息,并在这个消息中显示不可达的具体原因,原因记录在 ICMP 包头的代码字段。
由此,根据 ICMP 不可达的具体消息,发送端主机也就可以了解此次发送不可达的具体原因。
举例 6 种常见的目标不可达类型的代码:
a. 网络不可达代码为 0
IP 地址是分为网络号和主机号的,所以当路由器中的路由器表匹配不到接收方 IP 的网络号,就通过 ICMP 协议以网络不可达(Network Unreachable
)的原因告知主机。
自从不再有网络分类以后,网络不可达也渐渐不再使用了。
b. 主机不可达代码为 1
当路由表中没有该主机的信息,或者该主机没有连接到网络,那么会通过 ICMP 协议以主机不可达(Host Unreachable
)的原因告知主机。
c. 协议不可达代码为 2
当主机使用 TCP 协议访问对端主机时,能找到对端的主机了,可是对端主机的防火墙已经禁止 TCP 协议访问,那么会通过 ICMP 协议以协议不可达的原因告知主机。
d. 端口不可达代码为 3
当主机访问对端主机 8080 端口时,这次能找到对端主机了,防火墙也没有限制,可是发现对端主机没有进程监听 8080 端口,那么会通过 ICMP 协议以端口不可达的原因告知主机。
e. 需要进行分片但设置了不分片位代码为 4
发送端主机发送 IP 数据报时,将 IP 首部的分片禁止标志位设置为1
。根据这个标志位,途中的路由器遇到超过 MTU 大小的数据包时,不会进行分片,而是直接抛弃。随后,通过一个 ICMP 的不可达消息类型,代码为 4 的报文,告知发送端主机。
原点抑制消息(ICMP Source Quench Message) —— 类型
4
在使用低速广域线路的情况下,连接 WAN 的路由器可能会遇到网络拥堵的问题。
ICMP
原点抑制消息的目的就是为了缓和这种拥堵情况。
当路由器向低速线路发送数据时,其发送队列的缓存变为零而无法发送出去时,可以向 IP 包的源地址发送一个 ICMP 原点抑制消息。
收到这个消息的主机借此了解在整个线路的某一处发生了拥堵的情况,从而增大 IP 包的传输间隔,减少网络拥堵的情况。
然而,由于这种 ICMP 可能会引起不公平的网络通信,一般不被使用。
重定向消息(ICMP Redirect Message) —— 类型
5
如果路由器发现发送端主机使用了「不是最优」的路径发送数据,那么它会返回一个 ICMP 重定向消息给这个主机。
在这个消息中包含了最合适的路由信息和源数据。这主要发生在路由器持有更好的路由信息的情况下。路由器会通过这样的 ICMP 消息告知发送端,让它下次发给另外一个路由器。
超时消息(ICMP Time Exceeded Message) —— 类型
11
IP 包中有一个字段叫做 TTL
(Time To Live
,生存周期),它的值随着每经过一次路由器就会减 1,直到减到 0 时该 IP 包会被丢弃。
此时,路由器将会发送一个 ICMP 超时消息给发送端主机,并通知该包已被丢弃。
设置 IP 包生存周期的主要目的,是为了在路由控制遇到问题发生循环状况时,避免 IP 包无休止地在网络上被转发。
此外,有时可以用 TTL 控制包的到达范围,例如设置一个较小的 TTL 值。
ping —— 查询报文类型的使用
ping 是应用层命令,可以理解为它跟游戏或者聊天软件属于同一层。
同个子网下的主机 A 和 主机 B,主机 A 执行ping
主机 B 后,我们来看看其间发送了什么?
ping 命令执行的时候,源主机首先会构建一个 ICMP 回送请求消息数据包。
ICMP 数据包内包含多个字段,最重要的是两个:
- 第一个是类型,对于回送请求消息而言该字段为
8
; - 另外一个是序号,主要用于区分连续 ping 的时候发出的多个数据包。
每发出一个请求数据包,序号会自动加 1
。为了能够计算往返时间 RTT
,它会在报文的数据部分插入发送时间。
然后,由 ICMP 协议将这个数据包连同地址 192.168.1.2 一起交给 IP 层。IP 层将以 192.168.1.2 作为目的地址,本机 IP 地址作为源地址,协议字段设置为 1
表示是 ICMP
协议,再加上一些其他控制信息,构建一个 IP
数据包。
接下来,需要加入 MAC
头。如果在本地 ARP 映射表中查找出 IP 地址 192.168.1.2 所对应的 MAC 地址,则可以直接使用;如果没有,则需要发送 ARP
协议查询 MAC 地址,获得 MAC 地址后,由数据链路层构建一个数据帧,目的地址是 IP 层传过来的 MAC 地址,源地址则是本机的 MAC 地址;还要附加上一些控制信息,依据以太网的介质访问规则,将它们传送出去。
主机 B
收到这个数据帧后,先检查它的目的 MAC 地址,并和本机的 MAC 地址对比,如符合,则接收,否则就丢弃。
接收后检查该数据帧,将 IP 数据包从帧中提取出来,交给本机的 IP 层。同样,IP 层检查后,将有用的信息提取后交给 ICMP 协议。
主机 B
会构建一个 ICMP 回送响应消息数据包,回送响应数据包的类型字段为 0
,序号为接收到的请求数据包中的序号,然后再发送出去给主机 A。
在规定的时候间内,源主机如果没有接到 ICMP 的应答包,则说明目标主机不可达;如果接收到了 ICMP 回送响应消息,则说明目标主机可达。
此时,源主机会检查,用当前时刻减去该数据包最初从源主机上发出的时刻,就是 ICMP 数据包的时间延迟。
traceroute —— 差错报文类型的使用
有一款充分利用 ICMP 差错报文类型的应用叫做 traceroute
(在 UNIX、MacOS 中是这个命令,而在 Windows 中对等的命令叫做 tracert )。
1. traceroute 作用一
traceroute 的第一个作用就是故意设置特殊的 TTL,来追踪去往目的地时沿途经过的路由器。
traceroute 的参数指向某个目的 IP 地址:
traceroute 192.168.1.100
这个作用是如何工作的呢?
它的原理就是利用 IP 包的生存期限 从 1
开始按照顺序递增的同时发送 UDP 包,强制接收 ICMP 超时消息的一种方法。
比如,将 TTL 设置 为 1
,则遇到第一个路由器,就牺牲了,接着返回 ICMP 差错报文网络包,类型是时间超时。
接下来将 TTL 设置为 2
,第一个路由器过了,遇到第二个路由器也牺牲了,也同时返回了 ICMP 差错报文数据包,如此往复,直到到达目的主机。
这样的过程,traceroute 就可以拿到了所有的路由器 IP。
当然有的路由器根本就不会返回这个 ICMP,所以对于有的公网地址,是看不到中间经过的路由的。
发送方如何知道发出的 UDP 包是否到达了目的主机呢?
traceroute 在发送 UDP
包时,会填入一个不可能的端口号值作为 UDP 目标端口号:33434。然后对于每个下一个探针,它都会增加一个,这些端口都是通常认为不会被使用,不过,没有人知道当某些应用程序监听此类端口时会发生什么。
当目的主机,收到 UDP 包后,会返回 ICMP 差错报文消息,但这个差错报文消息的类型是「端口不可达」。
所以,当差错报文类型是端口不可达时,说明发送方发出的 UDP 包到达了目的主机。
2. traceroute 作用二
traceroute 还有一个作用是故意设置不分片,从而确定路径的 MTU。
这么做是为了什么?
这样做的目的是为了路径 MTU 发现。
因为有的时候我们并不知道路由器的 MTU
大小,以太网的数据链路上的 MTU
通常是 1500
字节,但是非以太网的 MTU
值就不一样了,所以我们要知道 MTU
的大小,从而控制发送的包大小。
它的工作原理如下:
首先在发送端主机发送 IP
数据报时,将 IP
包首部的分片禁止标志位设置为 1。根据这个标志位,途中的路由器不会对大数据包进行分片,而是将包丢弃。
随后,通过一个 ICMP 的不可达消息将数据链路上 MTU 的值一起给发送主机,不可达消息的类型为「需要进行分片但设置了不分片位」。
发送主机端每次收到 ICMP 差错报文时就减少包的大小,以此来定位一个合适的 MTU
值,以便能到达目标主机。
断网了,能不能 ping 本机 127.0.0.1
然后在控制台输入ping 127.0.0.1
。
$ ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.080 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.093 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.074 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.079 ms
64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.079 ms
^C
--- 127.0.0.1 ping statistics ---
5 packets transmitted, 5 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.074/0.081/0.093/0.006 ms
说明,拔了网线,ping 127.0.0.1
是能 ping 通的。
什么是 127.0.0.1
首先,这是个 IPV4
地址。
IPV4
地址有 32
位,一个字节有 8
位,共 4
个字节。
其中127 开头的都属于回环地址,也是 IPV4
的特殊地址,没什么道理,就是人为规定的。
而127.0.0.1
是众多回环地址中的一个。之所以不是 127.0.0.2
,而是 127.0.0.1
,是因为源码里就是这么定义的,也没什么道理。
/* Address to loopback in software to local host. */
#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */
在 IPV4 下的回环地址是 127.0.0.1
,在IPV6
下,表达为 ::1
。中间把连续的 0给省略了,之所以不是7 个 冒号,而是2 个冒号: , 是因为一个 IPV6 地址中只允许出现⼀次两个连续的冒号。
所以:在 IPV4 下用 ping 127.0.0.1 命令 = 在 IPV6 下用 ping6 ::1 命令。
TCP 发数据和 ping 的区别
一般情况下,我们会使用 TCP 进行网络数据传输,那么我们可以看下它和 ping 的区别。
PS:下图中有一处画错了,右边是 tcp 数据,而不是 ping 数据,我偷懒就不重画了。
在 TCP 传输中创建的方式是 socket(AF_INET, SOCK_STREAM, 0);
,其中 AF_INET
表示将使用 IPV4 里 host:port 的方式去解析待会你输入的网络地址。SOCK_STREAM
是指使用面向字节流的 TCP 协议,工作在传输层。
ping 中创建 socket
的时候用的是 socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)
,SOCK_RAW
是原始套接字 ,工作在网络层, 所以构建ICMP
(网络层协议)的数据,是再合适不过了。
为什么断网了还能 ping 通 127.0.0.1
有网的情况下,ping 最后是通过网卡将数据发送出去的。
那么断网的情况下,网卡已经不工作了,ping 回环地址却一切正常,我们可以看下这种情况下的工作原理。
从应用层到传输层再到网络层。这段路径跟 ping 外网的时候是几乎是一样的。到了网络层,系统会根据目的 IP,在路由表中获取对应的路由信息,而这其中就包含选择哪个网卡把消息发出。
当发现目标 IP 是外网 IP时,会从”真网卡”发出。
当发现目标 IP 是回环地址时,就会选择本地网卡。
本地网卡,其实就是个“假网卡”,它不像”真网卡”那样有个ring buffer
什么的,”假网卡”会把数据推到一个叫 input_pkt_queue
的 **链表** 中。这个链表,其实是所有网卡共享的,上面挂着发给本机的各种消息。消息被发送到这个链表后,会再触发一个软中断。
专门处理软中断的工具人“ksoftirqd” (这是个内核线程),它在收到软中断后就会立马去链表里把消息取出,然后顺着数据链路层、网络层等层层往上传递最后给到应用程序。
ping 回环地址和 ping 本机地址有什么区别
我们在 mac(Linux 也是这个命令)里执行 ifconfig
。Windows 是 ipconfig
$ ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
inet 127.0.0.1 netmask 0xff000000
...
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
inet 192.168.31.6 netmask 0xffffff00 broadcast 192.168.31.255
...
lo0,表示本地回环接口,对应的地址,就是我们前面提到的 127.0.0.1 ,也就是回环地址。
eth0,表示本机第一块网卡,对应的 IP 地址是192.168.31.6,管它叫本机 IP。
ping 本机 IP 跟 ping 回环地址一样,相关的网络数据,都是走的 lo0,本地回环接口,也就是前面提到的“假网卡”。
只要走了本地回环接口,那数据都不会发送到网络中,在本机网络协议栈中兜一圈,就发回来了。因此 ping 回环地址和 ping 本机地址没有区别。
127.0.0.1 和 localhost 以及 0.0.0.0 有区别吗
首先 localhost
就不叫 IP
,它是一个域名,就跟 "baidu.com"
,是一个形式的东西,只不过默认会把它解析为 127.0.0.1
,当然这可以在 /etc/hosts
文件下进行修改。
所以默认情况下,使用 localhost
跟使用 127.0.0.1
确实是没区别的。
其次就是 0.0.0.0
,执行 ping 0.0.0.0 ,是会失败的,因为它在IPV4
中表示的是无效的目标地址。
$ ping 0.0.0.0
PING 0.0.0.0 (0.0.0.0): 56 data bytes
ping: sendto: No route to host
ping: sendto: No route to host
但它还是很有用处的,回想下,我们启动服务器的时候,一般会 listen
一个 IP 和端口,等待客户端的连接。
如果此时 listen
的是本机的 0.0.0.0
, 那么它表示本机上的所有 IPV4 地址。
/* Address to accept any incoming messages. */
#define INADDR_ANY ((unsigned long int) 0x00000000) /* 0.0.0.0 */
举个例子。刚刚提到的 127.0.0.1
和 192.168.31.6
,都是本机的 IPV4 地址,如果监听 0.0.0.0
,那么用上面两个地址,都能访问到这个服务器。
当然, 客户端 connect
时,不能使用 0.0.0.0
。必须指明要连接哪个服务器 IP。