终于来到了网络的最后一篇,继续加油!
IP 知识全家桶
IP 基本认识
IP 在 TCP/IP 参考模型中处于第三层 ,也就是网络层。
网络层的主要作用是:实现主机与主机之间的通信,也叫点对点(end to end)通信。
使用 IP 的最终目的,就是在整个网络系统中,将数据包发送给最终的目的主机。
这里对比一下 IP(网络层) 的 MAC(数据链路层)的区别:IP 是用来在主机之间通信的,而 MAC 的作用是实现「直连」的两个设备之间通信 ,而 IP 则负责在「没有直连」的两个网络之间进行通信传输。可以看下图感受一下:
计算机网络中也需要「数据链路层」和「网络层」这个分层 才能实现向最终目标地址的通信。在传输过程中,源 IP 地址和目标 IP 地址是不会变化的 (前提是未使用 NAT 网络),只有源 MAC 地址和目标 MAC 地址不断变化。
IP 地址基础知识
IP 地址(IPv4 地址)由 32 位正整数来表示,IP 地址在计算机是以二进制的方式处理的。
而人类为了方便记忆采用了点分十进制的标记方式,也就是将 32 位 IP 地址以每 8 位为组,共分为 4 组,每组以「.」隔开,再将每组转换成十进制。所以说,IP 地址最大也就是 2^32,大致 43 亿台计算机。
实际上,IP 地址的分配是依据网卡来完成;如路由器、服务器等都有 2 个以上网卡,那就会有 2 个以上的 IP 地址。
可以根据更换 IP 地址的技术 NAT 来完成超过 43 亿台计算机的连接。
IP 地址分类
可以分为 5 类 ,分别为 A、B、C、D、E 类。
- A、B、C类地址
其中对于 A、B、C 类主要分为两个部分,分别是网络号和主机号 。可以看下面的表格:
这里以 C 类地址距离,主机号共占 8 位,最大主机个数为:2^8 - 2 = 254。减去 2 就是因为 IP 地址中有两个 IP 是特殊的,分别是主机号全为 1 和 全为 0 地址 。主机号全为 1 指定某个网络下所有主机,用于广播;主机号全为 0 指定某个网络。
引出新的一点,广播地址 的作用是用于在同一个链路中相互连接的主机之间发送数据包 。广播地址可以分为本地广播 和直接广播两种。
- 在本网络内广播叫做本地广播。
- 在不同网络之间的广播叫做直接广播。但是会有安全问题,多数路由器都设置为不转发。
- D、E 类地址
D 类和 E 类是没有主机号的,所以不可用于主机 IP,D 类多用于多播,E 类是预留分类暂时未使用。
多播用于将包发送给特定组内的所有主机。
多播使用的 D 类地址,其前四位是 1110 就表示是多播地址 ,而剩下的 28 位是多播的组编号。从 224.0.0.0 ~ 239.255.255.255 都是多播的可用范围,其划分为以下三类:
- 224.0.0.0 ~ 224.0.0.255:预留的组播地址,只能用在局域网中,路由器不会转发;
- 224.0.1.0 ~ 2238.255.255.255:用户可用的组播地址,可用于 Internet;
- 239.0.0.0 ~ 239.255.255.255:本地管理组播地址,可供内部网在内部使用,尽在特定的本地范围内有效。
IP 分类的优点很明显,可以很快找出网络地址和主机地址。IP 分类可以直接根据 IP 地址来看:
当然,IP 缺点也有两个:
- 同一网络下没有地址层次,缺少了地址的灵活性;
- A、B、C 类地址,不能很好的与现实网络匹配;C 类地址最大主机数量太少,B 类地址最大主机数量太多。
无分类地址 CIDR
正因为 IP 分类存在许多缺点,所以后面提出了无分类地址的方案,即 CIDR。
这种方式不再有分类地址的概念,32 比特的 IP 地址被划分为两部分,前面是网络号,后面是主机号。
表示形式 a.b.c.d/x ,其中 /x 表示前 x 位属于网络号 , x 的范围是 0 ~ 32,这就使得 IP 地址更加灵活。示例如下:
还有另一种划分网络号与主机号形式,那就是子网掩码,掩码的意思就是掩盖掉主机号,剩余的就是网络号。将子网掩码和 IP 地址按位计算 AND,就可得到网络号。
- 网络号和主机号存在的意义如下:
因为两台计算机要通讯,首先要判断是否处于同一个广播域内,即网络地址是否相同。如果网络地址相同,表明接受方在本网络上,那么可以把数据包直接发送到目标主机。
路由器寻址工作中,也就是通过这样的方式来找到对应的网络号的,进而把数据包转发给对应的网络内。
- 子网划分
子网划分实际上是将主机地址 分为两个部分:子网网络地址和子网主机地址。如下:
也就是借助子网掩码的最后一段,来进行主机地址的分类。最后一段中为 1 的部分就是从主机号中借用的子网网络地址。
这里有一个例子,对一个 C 类地址进行子网划分:
划分后结果如下:
公有 IP 地址与私有 IP 地址
对于 A、B、C 类地址,实际分为公有 IP 和私有 IP:
公有 IP 地址是有个组织统一分配的,假设你要开一个博客网站,那么你就需要去申请购买。并且公有 IP 地址基本上在整个互联网范围内需要保持位移。
私有 IP 地址通常是内部的 IT 人员管理,公有 IP 地址是由 ICANN 组织管理,中文叫「互联网名称与数字地址分配机构」。他们是按照州的方式来分配:
IP 地址与路由控制
IP地址的网络地址 这一部分是用于进行路由控制。
在发送 IP 包时,首先要确定 IP 包首部中的目标地址,再从路由控制表中找到与该地址具有相同网络地址的记录 ,根据该记录将 IP 包转发给相应的下一个路由器。如果路由控制表中存在多条相同网络地址的记录,就选择相同位数最多的网络地址,也就是最长匹配。
请看如下示例:
- 主机 A 要发送一个 IP 包,其源地址是 10.1.1.30 和目标地址是 10.1.2.10,由于没有在主机 A 的路由表找到与目标地址 10.1.2.10 相同的网络地址,于是包被转发到默认路由(路由器 1)
- 路由器 1 收到 IP 包后,也在路由器 1 的路由表匹配与目标地址相同的网络地址记录,发现匹配到了,于是把 IP 数据包转发到了 10.1.0.2 这台路由器 2;
- 路由器 2 收到后,同样对比自身的路由表,发现匹配到了,于是把 IP 包从路由器 2 的 10.1.2.1 这个接口出去,最终经过交换机把 IP 数据包转发到了目标主机。
环回地址 是在同一台计算机上的程序之间进行网络通信时所使用的一个默认地址 。计算机使用一个特殊的 IP 地址 127.0.0.1 作为环回地址。与该地址具有相同意义的是叫做 localhost 的主机名。使用这个 IP 或主机名时,数据包不会流向网络。
IP 分片与重组
每种数据链路的最大传输单元 MTU 都是不相同的,如 FDDI 数据链路 MTU 4352、以太网的MTU 是 1500 字节等。
当 IP 数据包大小大于 MTU 时, IP 数据包就会被分片 。经过分片之后的 IP 数据报在被重组的时候,只能由目标主机进行,路由器是不会进行重组的。
在分片传输中,一旦某个分片丢失,则会造成整个 IP 数据报作废,所以 TCP 引入了 MSS 也就是在 TCP 层进行分片而不是由 IP 层分片,对于 UDP 则尽量不要发送大于 MTU 的数据报文。
IPv6 基本认识
IPv6 除了有更多的地址之外,还有更好的安全性和扩展性,说简单点就是 IPv6 相比与 IPv4 有更好的网络体验。
- IPv6 亮点
如下:
-
IPv6 可自动配置,即使没有 DHCP 服务器也可以实现自动分配IP地址;
-
IPv6 包头包首部长度采用固定的值 40 字节 ,去掉了包头校验和,简化了首部结构,提高了传输性能;
-
Pv6 有应对伪造 IP 地址的网络安全功能以及防止线路窃听的功能,大大提升了安全性。
-
IPv6 标识方法
IPv6 地址长度是 128 位,是以每 16 位作为一组,每组用冒号 「:」 隔开。如下:
如果出现连续的 0 时还可以将这些 0 省略,并用两个冒号 「::」隔开。但是,一个 IP 地址中只允许出现一次连续两个冒号。
- IPv6 地址结构
组要有以下类型地址:
- 单播地址,用于一对一通信;
- 组播地址,用于一对多通信;
- 任播地址,用于通信最近的节点,最近节点由路由协议决定;
- 没有广播地址。
- IPv6 单播地址
主要也划分了三类单播地址:
- 在同一链路单播通信,不经过路由器,可以使用链路本地单播地址,IPv4 没有此类型;
- 在内网里单播通信,可以使用唯一本地地址,相当于 IPv4 的私有 IP;
- 在互联网通信,可以使用全局单播地址,相当于 IPv4 的公有 IP。
IPv4 与 IPv6 首部
差异如下:
IPv6 有了如下改进:
- 取消了首部校验和字段。 因为在数据链路层和传输层都会校验,因此 IPv6 直接取消了 IP 的校验。
- 取消了分片/重新组装相关字段。 分片与重组是耗时的过程,IPv6 不允许在中间路由器进行分片与重组,这种操作只能在源与目标主机,这将大大提高了路由器转发的速度。
- 取消选项字段。 选项字段不再是标准 IP 首部的一部分了,但它并没有消失,而是可能出现在 IPv6 首部中的「下一个首部」指出的位置上。删除该选项字段使的 IPv6 的首部成为固定长度的 40 字节。
IP 协议相关技术
跟 IP 协议相关的技术也不少,接下来说说与 IP 协议相关的重要且常见的技术。
- DNS 域名解析
- ARP 与 RARP 协议
- DHCP 动态获取 IP 地址
- NAT 网络地址转换
- ICMP 互联网控制报文协议
- IGMP 因特网组管理协议
DNS
一般上网都是使用域名,实现这一技术的就是 DNS 域名解析,DNS 可以将域名网址自动转换为具体的 IP 地址。
DNS 中的域名都是用句点来分隔 的,比如 www.server.com,这里的句点代表了不同层次之间的界限 。并且,越靠右的位置层级越高。
所以,域名的层级关系类似树状结构:
- 根 DNS 服务器
- 顶级域 DNS 服务器(com)
- 权威 DNS 服务器(server.com)
根域的 DNS 服务器信息保存在互联网中所有的 DNS 服务器中。因此,客户端只要能够找到任意一台 DNS 服务器,就可以通过它找到根域 DNS 服务器,在一路向下寻找。
- 域名解析流程
浏览器首先看一下自己的缓存里有没有,如果没有就向操作系统的缓存要,还没有就检查本机域名解析文件 hosts,如果没有,就会 DNS 服务器进行查询:
- 客户端首先会发出一个 DNS 请求,问 www.server.com 的 IP 是啥,并发送给本地 DNS 服务器(客户端 TCP/IP 设置中填写的 DNS 服务器地址)
- 本地域名服务器收到客户端的请求后,如果缓存里的表格能找到 www.server.com,则它直接返回 IP 地址。没有,本地 DNS 会去问它的根域名服务器。根域名服务器是最高层次的,不直接用于域名解析但可以知名道路。
- 根 DNS 收到来自本地 DNS 的请求后,发现后置是 .com,就会给 .com 的顶级域名服务器地址。
- 本地 DNS 收到顶级域名服务器的地址后,发起请求。
- 顶级域名服务器会给出 server.com 区域的 DNS 服务器地址。
- 本地 DNS 于是转向问权威 DNS 服务器。server.com 的权威 DNS 服务器,它是域名解析结果的原出处。
- 权威 DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS。
- 本地 DNS 再将 IP 地址返回客户端,客户端和目标建立连接。
可以看一下下图的总结:
ARP
在传输一个 IP 数据报的时候,确定了源 IP 地址和目标 IP 地址后,就会通过主机「路由表」确定 IP数据包下一跳。但是,网络层的下一层是数据链路层,还需要知道「下一跳」的 MAC 地址。由于主机的路由表中可以找到下一跳的 IP 地址,所以可以通过 ARP 协议,求得下一跳的 MAC 地址。
ARP 是借助 ARP 请求与 ARP 响应两种类型的包确定 MAC 地址的。
- 主机会通过广播发送 ARP 请求,这个包中包含了想要知道的 MAC 地址的主机 IP 地址。
- 当同个链路中的所有设备收到 ARP 请求时,会去拆开 ARP 请求包里的内容,如果 ARP 请求包的目标 IP 地址与自己 IP 地址匹配,那这个设备就会将自己的 MAC 地址塞入 ARP 响应包返回给主机。
操作系统通常会把第一次通过 ARP 获取的 MAC 地址缓存起来,以便下次直接从缓存中找到对应的 MAC 地址。
- RARP 协议
ARP 协议是已知 IP 地址求 MAC 地址,那 RARP 协议正好相反,它是已知 MAC 地址求 IP 地址。
通常这需要架设一台 RARP 服务器,在这个服务器上注册设备的 MAC 地址及其 IP 地址。之后,该设备会发送请求 IP 的信息,RARP 服务器接收到之后就会发送分配的 IP 地址给到这个设备。
DHCP
电脑通常都是通过 DHCP 动态获取 IP 地址。
可以通过 4 个步骤来获取 IP。
DHCP 客户端进程监听的是 68 端口号,DHCP 服务端进程监听的是 67 端口号。
4 个步骤解析如下:
- 客户端首先发起 DHCP 发现报文(DHCP DISCOVER) 的 IP 数据报,由于客户端没有 IP 地址,也不知道 DHCP 服务器的地址,所以使用的是 UDP 广播 通信,其使用的广播目的地址是 255.255.255.255(端口 67),并使用 0.0.0.0(端口 68)作为源 IP 地址。DHCP 客户端将该 IP 数据报传递给链路层,链路层然后将帧广播到所有的网络中设备。
- HCP 服务器收到 DHCP 发现报文时,用 DHCP 提供报文(DHCP OFFER)向客户端做出响应 。该报文仍然使用 IP 广播地址 255.255.255.255 ,该报文信息携带服务器提供可租约的 IP 地址、子网掩码、默认网关、DNS 服务器以及 IP 地址租用期。
- 客户端收到一个或多个服务器的 DHCP 提供报文后,从中选择一个服务器 ,并向选中的服务器发送 DHCP 请求报文(DHCP REQUEST)进行响应,回显配置的参数。
- 最后,服务端用 DHCP ACK 报文对 DHCP 请求报文进行响应,应答所要求的参数。
一旦客户端收到 DHCP ACK 后,交互便完成了,并且客户端能够在租用期内使用 DHCP 服务器分配的 IP 地址。
如果租约的 DHCP IP 地址快到期,客户端会向服务器发送 DHCP 请求报文:
- 服务器如果同意继续租用,则用 DHCP ACK 报文进行应答,客户端就会延长租期。
- 服务器如果不同意继续租用,则用 DHCP NACK 报文,客户端就要停止使用租约的 IP 地址。
DHCP 交互中,全程都是使用 UDP 广播通信。
这就引发了一个问题,如果 DHCP 服务器和客户端不在一个局域网,就无法完成通讯。为了解决这一问题,就出现了 DHCP 中继代理 。有了 DHCP 中继代理以后,对不同网段的 IP 地址分配也可以由 一个 DHCP 服务器统一进行管理。
解析如下:
- DHCP 客户端会向 DHCP 中继代理发送 DHCP 请求包,而 DHCP 中继代理在收到这个广播包后,再以单播的形式发给 DHCP 服务器。
- 服务器端收到该包以后再向 DHCP 中继代理返回应答,并由 DHCP 中继代理将此包广播给 DHCP 客户端。
NAT
提出了一种网络地址转换 NAT 的方法,再次缓解了 IPv4 地址耗尽的问题。
简单来说,就是在主机对外部通信时,把私有 IP 地址转换成公有 IP 地址。
由于绝大多数的网络应用都是使用传输层协议 TCP 或 UDP 来传输数据,因此可以把 IP 地址 + 端口号一起进行转换 。这种转换技术就叫网络地址与端口转换 NAPT。可以看下图:
此时,两个私有 IP 地址都转换 IP 地址为公有地址 120.229.175.121 ,但是以不同的端口号作为区分。
于是,生成一个 NAPT 路由器的转换表,就可以正确地转换地址跟端口的组合,令客户端A、B能同时与服务器通讯。
这种转换表在 NAT 路由器上自动生成。例如,TCP 情况下,建立连接的首次握手时,SYN 包已经发出就会生成这个表。而后随着收到关闭连接的 FIN 包确认应答从表中被删除。
由于 NAT/NAPT 都依赖于自己的转换表,因此会有以下的问题:
- 外部无法主动与 NAT 服务器建立连接,因为 NAPT 转换表没有转换记录;
- 转换表的生成与转换操作都会产生性能开销;
- 通信过程中,如果 NAT 路由器重启,所有的 TCP 都会被重置。
以上问题,可以用如下方法解决:
- 改用 IPv6,地址多于是都可以配置一个共有 IP 地址;
- NAT 穿透技术
NAT 穿越技术拥有这样的功能,它能够让网络应用程序主动发现自己位于 NAT 设备之后,能主动获得 NAT 设备的公有 IP,并为自己建立端口映射条目,这些都是 NAT 设备的应用程序自动完成的。也就是说,是客户端主动从 NAT 设备来获取公有 IP 地址,然后自己建立端口映射条目并以此对外通信。
ICMP
ICMP 全称是 Internet Control Message Protocol,也就是互联网控制报文协议。
ICMP 主要的功能包括:确认 IP 包是否成功送达目标地址、报告发送过程中 IP 包被废弃的原因和改善网络设置等。
如果 IP 通信过程中,某个 IP 包未能达到目标地址,那么这个具体原因就是由 ICMP 负责通知。如下:
ICMP 的何种消息通知是使用 IP 进行发送的。
ICMP 大致可分为两大类:
- 诊断的查询消息,也就是「查询报文类型」
- 通知出错原因的错误消息,也就是「差错报文类型」
IGMP
在前面我们知道了组播地址,也就是 D 类地址 ,既然是组播 ,那就说明是只有一组的主机能收到数据包,不在一组的主机不能收到数组包,这就需要 IGMP 协议来管理。
IGMP 是因特网组管理协议,工作在主机(组播成员)和最后一跳路由之间。
- IGMP 报文向路由器申请加入和退出组播组,默认情况下路由器是不会转发组播包到连接中的主机,除非主机通过 IGMP 加入到组播组,主机申请加入到组播组时,路由器就会记录 IGMP 路由器表,路由器后续就会转发组播包到对应的主机了。
- IGMP 报文采用 IP 封装,IP 头部的协议号为 2,而且 TTL 字段值通常为 1,因为 IGMP 是工作在主机与连接的路由器之间。
IGMP 一共有三个版本,这里之后就学习一下 IGMPv2。
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 命令。这次就学一下具体的工作原理。
IP 协议助手 ------ ICMP 协议
这里在上一章节有所介绍,这里不赘述。
- ICMP 包头格式
ICMP 是封装在 IP 里面的,工作在网络层:
ICMP 主要可以分为两个大类:查询报文类型以及差错报文类型。
查询报文类型
会送消息------类型 0 和 8。
回送消息 用于进行通信的主机或路由器之间,判断所发送的数据包是否已经成功到达对端的一种消息,ping 命令就是利用这个消息实现。
可以向对端主机发送回送请求的消息(ICMP Echo Request Message,类型 8),也可以接收对端主机发回来的回送应答消息(ICMP Echo Reply Message,类型 0)。
相比较原生 ICMP,多了两个字段:
- 标识符:用以区分是哪个应用程序发 ICMP 包,比如用进程 PID 作为标识符;
- 序号:从 0 开始,每发送一次新的回送请求就会加 1,用来确认网络包是否有丢失。
在选项数据 中,ping 还会存放发送请求的时间值,来计算往返时间,说明路程的长短。
差错报文类型
说明几个常用的 ICMP 差错报文的例子:
- 目标不可达消息 ------ 类型 为 3
- 原点抑制消息 ------ 类型 4
- 重定向消息 ------ 类型 5
- 超时消息 ------ 类型 11
目标不可达消息 ------ 类型为 3
IP 路由器无法将 IP 数据包发送给目标地址时,会给发送端主机返回一个目标不可达的 ICMP 消息 ,并在这个消息中显示不可达的具体原因,原因记录在 ICMP 包头的代码字段。有常见的 6 种不可达代码:
这里有非常详细的距离:目标不可达消息
原点抑制消息 ------ 类型 4
使用低速广域线路的情况下,连接 WAN 的路由器可能会遇到网络拥堵的问题。
ICMP 的原点抑制消息就是为了缓和这种拥堵情况。
当路由器向低速线路发送数据时,其发送队列的缓存变为零而无法发送出去时,可以向 IP 包的源地址发送一个 ICMP 原点抑制消息。主机收到消息就会了解到拥堵,从而增大 IP 包的传输间隔,减少网络拥堵。
然而,由于这种 ICMP 可能会引起不公平的网络通信 ,一般不被使用。
重定向消息 ------ 类型 5
如果路由器发现发送端主机使用了「不是最优」的路径发送数据 ,那么它会返回一个 ICMP 重定向消息给这个主机。
在这个消息中包含了最合适的路由信息和源数据。这主要发生在路由器持有更好的路由信息的情况下。路由器会通过这样的 ICMP 消息告知发送端,让它下次发给另外一个路由器。
超时消息 ------ 类型 11
IP 包中有一个字段叫做 TTL (Time To Live,生存周期),它的值随着每经过一次路由器就会减 1,直到减到 0 时该 IP 包会被丢弃。
此时,路由器将会发送一个 ICMP 超时消息给发送端主机,并通知该包已被丢弃。生存周期存在的目的是为了防止在路由控制遇到问题发生循环状况时,IP 包无休止的在网络上被转发。
当然,也可以用 TTL 控制包的到达范围,例如设置较小的 TTL 值。
ping ------ 查询报文类型的使用
看 ping 的发送和接收过程。
ping 命令执行,源主机首先会构建一个 ICMP 回送请求消息数据包。其中最重要的是两个字段:
- 类型:对于回送请求消息而言该字段为 8;
- 序号:用于区分连续 ping 的多个数据包。
每发出一个请求数据包,序号会自动加 1 。为了能够计算往返时间 RTT ,它会在报文的数据部分插入发送时间。
然后,由 ICMP 协议将数据包连同 IP 地址一起交给 IP 层。IP 层会将这个地址作为目的地址,本机 IP 地址作为源地址,协议字段设置为 1 表示是 ICMP 协议,以此构建数据包:
接下来加入 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 数据包的时间延迟。
总体流程如下:
ping 这个程序是使用了 ICMP 里面的 ECHO REQUEST(类型为 8 ) 和 ECHO REPLY(类型为 0)。
traceroute ------ 差错报文类型使用
充分利用 ICMP 差错报文类型的应用叫做 traceroute(在UNIX、MacOS中是这个,Windows 中叫做 tracert)。
作用一
第一个作用就是故意设置特殊的 TTL,来追踪去往目的地时沿途经过的路由器。
其参数指向某个目的 IP 地址。
原理就是利用 IP 包的生存期限 从 1 开始按照顺序递增的同时发送 UDP 包 ,强制接收 ICMP 超时消息。例如,将 TTL 设置为 1,那么遇到第一个路由器就牺牲了,接着返回 ICMP 差错报文网络包,类型是时间超时。
接下来设置 TTL 为 2,第一个路由器过了,遇到第二个也牺牲了,同时返回 ICMP 差错报文数据包,如此往复,直到到达目的主机。
以上,就能拿到所有路由器 IP。
不过对于有的路由器根本不返回 ICMP。
- 发送方确保 UDP 到达目的主机?
traceroute 在发送 UDP 包时,会填入一个不可能的端口号值作为 UDP 目标端口号:33434。然后对于每个下一个探针,它都会增加一个,这些端口都是通常认为不会被使用,不过监听此类端口不知道会发生什么。
当目的主机,收到 UDP 包后,会返回 ICMP 差错报文消息,但这个差错报文消息的类型是「端口不可达」。
所以,当差错报文类型是端口不可达 时,说明发送方发出的 UDP 包到达了目的主机。
作用二
故意设置不分片,从而确定路径的 MTU。
这样做的目的是为了路径MTU发现。
因为路由器的 MTU 是未知的。以太网的数据链路上的 MTU 通常是 1500 字节,非以太网就不一样了。MTU 大小获知后,就可以控制发送的包大小。
具体工作原理如下:
- 首先在发送端主机发送 IP 数据报时,将 IP 包首部的分片禁止标志位设置为 1。那么途中路由器对大数据包就不会分片,而是直接丢弃。
- 之后通过一个 ICMP 不可达消息将数据链路上 MTU 的值 一起给发送主机,不可达消息的类型为「需要进行分片但设置了不分片位」。
- 发送主机端每次收到 ICMP 差错报文时就减少包的大小,以此来定位一个合适的 MTU 值。
断网,能 ping 通 127.0.0.1?
什么是 127.0.0.1
这是 IPv4 地址。
127 开头的都属于回环地址。127.0.0.1 就是众多回环地址中的一个,就是定义的。
ping
上一章有分析过,底层就是 ICMP 协议。ICMP 与 IP 协议同属于网络层协议,但 ICMP 也是利用了 IP 协议进行消息传输。
TCP 发数据和 ping 区别
右边应该是 TCP 数据,不过无伤大雅。
TCP 传输中创建的方式是 socket(AF_INET, SOCK_STREAM, 0); ,其中 AF_INET 表示将使用 IPV4 里 host:port 的方式 去解析待会你输入的网络地址。SOCK_STREAM 是指使用面向字节流的 TCP 协议,工作在传输层。
创建好 socket 之后,可以调用 socket 的 sendto 接口。过程中进程从用户态进入内核态,最后调用 sock_sendmsg 方法。
进入传输层,带上 TCP 头,网络层带上 IP 头,数据链路层加上 MAC 头,就进入网卡的发送队列 ring buffer,顺着网卡发出。
ping 也是类似,只不过创建 socket 用的是 socket(AF_INET,SOCK_RAW,IPPROTO_ICMP) ,SOCK_RAW 是原始套接字 ,工作在网络层 。进入内核态之后也是调用 sock_sendmsg 方法,加入网络层后加上 ICMP 和 IP 头,数据链路层加上 MAC 头。
断网 ping 通 127.0.0.1
有网的情况下,ping 最后是通过网卡将数据发送出去的。
断网就会是如下工作原理:
从应用层到传输层再到网络层。这段路径跟ping外网的时候是几乎是一样的。到了网络层,系统会根据目的IP,在路由表中获取对应的路由信息,而这其中就包含选择哪个网卡把消息发出。
发现目标IP是外网IP时,会从"真网卡"发出;发现目标IP是回环地址 时,就会选择本地网卡。
本地网卡其实就是 "假网卡" ,它不像"真网卡"那样有个ring buffer什么的,"假网卡"会把数据推到一个叫 input_pkt_queue 的 链表 中。这个链表其实是所有网卡共享的,上面挂着发给本机的各种消息 。消息被发送到这个链表后,会再触发一个软中断。
专门处理软中断的工具人"ksoftirqd"(这是个内核线程),收到软中断后就会立马去链表里把消息取出,然后顺着数据链路层、网络层等层层往上传递最后给到应用程序。
ping 回环地址和通过TCP等各种协议发送数据到回环地址都是走这条路径。
ping 回环地址和 ping 本机地址区别
如果执行 ifconfig 命令,可以看到 lo0,表示本地回环接口,对应的地址,就是我们前面提到的 127.0.0.1,也就是回环地址。
eth0,表示本机第一块网卡 ,对应的IP地址是192.168.31.6,管它叫本机IP。
ping 本机IP 跟 ping 回环地址一样,相关的网络数据,都是走的 lo0,本地回环接口。
127.0.0.1 和 localhost 以及 0.0.0.0 区别
localhost 就不叫 IP,它是一个域名 ,就跟 "baidu.com",是一个形式的东西,只不过默认会被解析成 127.0.0.1 ,也可以在 /etc/hosts 进行修改。
默认 情况下,使用 localhost 跟使用 127.0.0.1 确实是没区别的。
执行 ping 0.0.0.0 是会失败的,因为在 IPv4 中表示的是无效的目标地址。
但它还是很有用处的,回想下,我们启动服务器的时候,一般会 listen 一个 IP 和端口,等待客户端的连接。如果此时 listen 的是本机的 0.0.0.0 , 那么它表示本机上的所有IPV4地址。