
前面我们学习了运输层如何为客户端和服务器输送数据的,提供进程端到端的通信。那么下面我们将学习网络层实际上是怎样实现主机到主机的通信服务的。几乎每个端系统都有网络层这一部分。所以,网络层必然是很复杂的。下面我将花费大量篇幅来介绍一下计算机网络层的知识。
网络层概述
网络层是 OSI 参考模型的第三层,它位于传输层和链路层之间,网络层的主要目的是实现两个端系统之间透明的数据传输。

网络层的作用从表面看上去非常简单,即将分组从一台主机移动到另外一台主机。为了实现这个功能,网络层需要两种功能
- 
转发
:因为在互联网中有很多
路由器
的存在,而路由器是构成互联网的根本,路由器最重要的一个功能就是
分组转发
,当一个分组到达某路由器的一条输入链路时,该路由器会将分组移动到适当的输出链路。转发是在数据平面中实现的唯一功能。
 
在网络中存在两种平面的选择 
数据平面(data plane):负责转发网络流量,如路由器交换机中的转发表(我们后面会说)。 
控制平面(control plane):控制网络的行为,比如网络路径的选择。 
- 
路由选择
:当分组由发送方流向接收方时,网络层必须选择这些分组的路径。计算这些路径选择的算法被称为
路由选择算法(routing algorithm)
。
 
那么此处就有一个问题,路由器怎么知道有哪些路径可以选择呢? 
转发表(forwarding table)。路由器通过检查数据包标头中字段的值,来定位转发表中的项来实现转发。标头中的值即对应着转发表中的值,这个值指出了分组将被转发的路由器输出链路。如下图所示

上图中有一个 1001 分组到达路由器后,首先会在转发表中进行索引,然后由路由选择算法决定分组要走的路径。每台路由器都有两种功能:转发和路由选择。下 面我们就来聊一聊路由器的工作原理。
路由器工作原理

- 
输入端口: 
输入端口(input port)
有很多功能。
线路终端功能
和
数据链路处理
功能,这两个功能实现了路由器的单个输入链路相关联的物理层和数据链路层。
输入端口查找/转发功能
对路由器的交换功能来说至关重要,由路由器的交换结构来决定输出端口,具体来讲应该是查询转发表来确定的。
 - 
交换结构: 
交换结构(Switching fabric)
就是将路由器的输入端口连接到它的输出端口。这种交换结构相当于是路由器内部的网络。
 - 
输出端口: 
输出端口(Output ports)
通过交换结构转发分组,并通过物理层和数据链路层的功能传输分组,因此,输出端口作为输入端口执行反向数据链接和物理层功能。
 - 
路由选择处理器: 
路由选择处理器(Routing processor)
在路由器内执行路由协议,维护路由表并执行网络管理功能。
 
上面只是这几个组件的简单介绍,其实这几个组件的组成并不像描述的那样简单,下面我们就来深入聊一聊这几个组件。
输入端口

每个输入端口中都有一个路由处理器维护的路由表的副本,根据路由处理器进行更新。这个路由表的副本能 够使每个输入端口进行切换,而无需经过路由处理器统一处理。
分散式的切换,这种方式避免了路 由选择器统一处理造成转发瓶颈。
一般这种路由器不是单独的路由器,而是工作站或者服务器充当的路由,这种路由器内部中,路由处理器其实就是 
CPU
,而输入端口其实只是
网卡
。
输入端口会根据转发表定位输出端口,然后再会进行分组转发,那么现在就有一个问题,是不是每一个分组都有自己的一条链路呢?如果分组数量非常大,到达亿级的话,也会有亿个输出端口路径吗?
我们的潜意识中显然不是的,来看下面一个例子。

如何实现呢? 
前缀(prefix)会与该表中的表项进行匹配。

如果存在一个匹配项,那么就会转发到对应的链路上,可能不好理解,我举个例子来说吧。
比如这时有一个分组是 11000011 10010101 00010000 0001100 到达,因为这个分组与 11000011 10010101 00010000 相匹配,所以路由器会转发到 0 链路接口上。如果一个前缀不匹配上面三个输出链路中的一种,那么路由器将向链路接口 3 进行转发。
最长前缀原则(longest prefix matching rule),最长匹配原则故名思义就是如果有两个匹配项一个长一个短的话,就匹配最长的。
交换结构
- 
经过内存交换:最开始的传统计算机就是使用 
内存交换
的,在输入端口和输出端口之间是通过 CPU 进行的。输入端口和输出端口的功能就好像传统操作系统中的 I/O 设备一样。当一个分组到达输入端口时,这个端口会首先以
中断
的方式向路由选择器发出信号,将分组从输入端口拷贝到内存中。然后,路由选择处理器从分组首部中提取目标地址,在转发表中找出适当的输出端口进行转发,同时将分组复制到输出端口的缓存中。
 
这里需要注意一点,如果内存带宽以每秒读取或者写入 B 个数据包,那么总的交换机吞吐量(数据包从输入端口到输出端口的总速率) 必须小于 B/2。 

- 
经过总线交换:在这种处理方式中,总线经由输入端口直接将分组传送到输出端口,中间不需要路由选择器的干预。总线的工作流程如下:输入端口给分组分配一个 
标签
,然后分组经由总线发送给所有的输出端口,每个输出端口都会判断标签中的端口和自己的是否匹配,如果匹配的话,那么这个输出端口就会把标签拆掉,这个标签只用于交换机内部跨越总线。如果同时有
多个
分组到达路由器的话,那么只有一个分组能够被处理,其他分组需要再进入交换结构前等待。
 

- 
经过互联网络交换:克服单一、共享式总线带宽限制的一种方法是使用一个更复杂的互联网络。如下图所示 
 

非阻塞的(non-blocking)的,也就是说 A -> X 的交叉点闭合不会影响 B -> Y 的链路。如果来自两个不同输入端口的两个分组其目的地为相同的输出端口的话,这种情况下只能有一个分组被交换,另外一个分组必须进行等待。
输出端口处理

丢包(packet loss),这就是我们说的在网络中丢包或者被路由器丢弃。
何时出现排队
输入队列
- 
使用网络互联的交换方式; 
 - 
假定所有链路的速度相同; 
 - 
在链路中一个分组由输入端口交换到输出端口所花的时间相同,从任意一个输入端口传送到给定的输出端口; 
 - 
分组按照 FCFS 的方式,只要输出端口不同,就可以进行并行传送。但是如果位于任意两个输入端口中的分组是发往同一个目的地的,那么其中的一个分组将被阻塞,而且必须在输入队列中等待,因为交换结构一次只能传输一个到指定端口。 
 

线路前部阻塞(Head-Of-The-Line, HOL)。
输出队列
耗尽输出端口的可用内存。
弃尾(drop-tail)的方法;一种是删除一个或多个已经排队的分组,从而来为新的分组腾出空间。
网络层的策略对 TCP 拥塞控制影响很大的就是路由器的分组丢弃策略。在最简单的情况下,路由器的队列通常都是按照 FCFS 的规则处理到来的分组。由于队列长度总是有限的,因此当队列已经满了的时候,以后再到达的所有分组(如果能够继续排队,这些分组都将排在队列的尾部)将都被丢弃。这就叫做尾部丢弃策略。 


分组调度(packet scheduleer)选择一个分组来进行传输,我们下面就会聊到分组传输。
分组调度
现在我们来讨论一下分组调度次序的问题,即排队的分组如何经输出链路传输的问题。我们生活中有无数排队的例子,但是我们生活中一般的排队算法都是 先来先服务(FCFS),也是先进先出(FIFO)。
先进先出
队列,只不过它现在是链路调度规则的排队模型。

优先级排队

通常情况下,每个优先级不同的分组有自己的优先级类,每个优先级类有自己的队列,分组传输会首先从优先级高的队列中进行,在同一类优先级的分组之间的选择通常是以 FIFO 的方式完成。
循环加权公平排队
循环加权公平规则(round robin queuing discipline)下,分组像使用优先级那样被分类。然而,在类之间却不存在严格的服务优先权。循环调度器在这些类之间循环轮流提供服务。如下图所示

保持工作排队(work-conserving queuing)的规则,就是说如果轮询的过程中发现有空队列,输出端口不会等待分组,而是继续轮询下面的队列。
IP 协议
IP 地址

中转站,一方面能够确保数据报是否丢失,另一方面能够控制数据报的转发,这个中转站就是我们前面聊过的路由器,这个转发过程就是
路由控制。
路由控制(Routing)是指将分组数据发送到最终目标地址的功能,即使网络复杂多变,也能够通过路由控制到达目标地址。因此,一个数据报能否到达目标主机,关键就在于路由器的控制。
跳,因为在一条链路中可能会布满很多路由器,路由器和路由器之间的数据报传送就是跳,比如你和隔壁老王通信,中间就可能会经过路由器 A-> 路由器 B -> 路由器 C 。
那么一跳的范围有多大呢? 
物理地址(Physical Address),它是用来确认网络设备位置的地址。在 OSI 网络模型中,网络层负责 IP 地址的定位,而数据链路层负责 MAC 地址的定位。MAC 地址用于在网络中唯一标示一个网卡,一台设备若有一或多个网卡,则每个网卡都需要并会有一个唯一的 MAC 地址,也就是说 MAC 地址和网卡是紧密联系在一起的。
多跳路由。
IP 地址定义
易读性的原则把 32 位的 IP 地址以 8 位为一组,分成四组,每组之间以
.进行分割,再将每组转换为十进制数。如下图所示

4294967296,大概能允许 43 亿台设备连接到网络。实际上真的如此吗?
网卡(NIC)进行配置,每一块网卡都会设置一个或者多个 IP 地址,而且通常一台路由器会有至少两块网卡,所以可以设置两个以上的 IP 地址,所以主机的数量远远达不到 43 亿。

IP 地址构造和分类
网络标识和
主机标识两部分组成,网络标识代表着网络地址,主机标识代表着主机地址。网络标识在数据链路的每个段配置不同的值。网络标识必须保证相互连接的每个段的地址都不重复。而相同段内相连的主机必须有相同的网络地址。IP 地址的
主机标识则不允许在同一网段内重复出现。
- 
A 类
:(1.0.0.0 - 126.0.0.0)(默认子网掩码:255.0.0.0 或 0xFF000000)第一个字节为网络号,后三个字节为主机号。该类 IP 地址的最前面为 0 ,所以地址的网络号取值于 1~126 之间。一般用于大型网络。
 - 
B 类
:(128.0.0.0 - 191.255.0.0)(默认子网掩码:255.255.0.0 或 0xFFFF0000)前两个字节为网络号,后两个字节为主机号。该类 IP 地址的最前面为 10 ,所以地址的网络号取值于 128~191 之间。一般用于中等规模网络。
 - 
C 类
:(192.0.0.0 - 223.255.255.0)(子网掩码:255.255.255.0 或 0xFFFFFF00)前三个字节为网络号,最后一个字节为主机号。该类 IP 地址的最前面为 110 ,所以地址的网络号取值于 192~223 之间。一般用于小型网络。
 - 
D 类
:是多播地址。该类 IP 地址的最前面为 1110 ,所以地址的网络号取值于 224~239 之间。一般用于多路广播用户。
 - 
E 类
:是保留地址。该类 IP 地址的最前面为 1111 ,所以地址的网络号取值于 240~255 之间。
 


子网掩码
子网掩码(subnet mask)又叫做网络掩码,它是一种用来指明一个 IP 地址的哪些位标识的是主机所在的网络。子网掩码是一个 32位 地址,用于屏蔽 IP 地址的一部分以区别网络标识和主机标识。

1表示 IP 网络地址的比特范围,
0表示 IP 主机地址的范围。将他们用十进制表示,那么这三类的表示如下

保留地址

IP 协议版本
IP 版本 4(IPv4)和
IP 版本6(IPv6)。IP 地址由二进制值组成,可驱动 Internet 上所有数据的路由。IPv4 地址的长度为 32 位,而 IPv6 地址的长度为 128 位。
Internet 分配号码机构(IANA)分配给区域 Internet 注册表(RIR),例如 APNIC,该机构负责根 DNS ,IP 寻址和其他 Internet 协议资源。
下面我们就一起认识一下 IP 协议中非常重要的两个版本 IPv4 和 IPv6。
IPv4
Internet Protocol version 4,是 Internet 协议的第四版。IPv4 是一种无连接的协议,这个协议会尽最大努力交付数据包,也就是说它不能保证任何数据包能到达目的地,也不能保证所有的数据包都会按照正确的顺序到达目标主机,这些都是由上层比如传输控制协议控制的。也就是说,单从 IP 看来,这是一个不可靠的协议。
前面我们讲过网络层分组被称为 
数据报
,所以我们接下来的叙述也会围绕着数据报展开。

- 
版本字段(Version)
占用 4 bit,通信双方使用的版本必须一致,对于 IPv4 版本来说,字段值是 4。
 - 
首部长度(Internet Header Length)
占用 4 bit,首部长度说明首部有多少 32 位(4 字节)。由于 IPv4 首部可能包含不确定的选项,因此这个字段被用来确定数据的偏移量。大多数 IP 不包含这个选项,所以一般首部长度设置为 5, 数据报为 20 字节 。
 - 
服务类型(Differential Services Codepoint,DSCP)
占用 6 bit,以便使用不同的 IP 数据报,比如一些低时延、高吞吐量和可靠性的数据报。服务类型如下表所示
 

- 
拥塞通告(Explicit Congestion Notification,ECN)
占用 2 bit,它允许在不丢弃报文的同时通知对方网络拥塞的发生。ECN 是一种可选的功能,仅当两端都支持并希望使用,且底层网络支持时才被使用。最开始 DSCP 和 ECN 统称为 TOS,也就是区分服务,但是后来被细化为了 DSCP 和 ECN。
 - 
数据报长度(Total Length)
占用 16 bit,这 16 位是包括在数据在内的总长度,理论上数据报的总长度为 2 的 16 次幂 - 1,最大长度是 65535 字节,但是实际上数据报很少有超过 1500 字节的。IP 规定所有主机都必须支持最小 576 字节的报文,但大多数现代主机支持更大的报文。当下层的数据链路协议的
最大传输单元(MTU)
字段的值小于 IP 报文长度时,报文就必须被分片。
 - 
标识符(Identification)
占用 16 bit,这个字段用来标识所有的分片,因为分片不一定会按序到达,所以到达目标主机的所有分片会进行重组,每产生一个数据报,计数器加1,并赋值给此字段。
 - 
标志(Flags)
占用 3 bit,标志用于控制和识别分片,这 3 位分别是
 - 
0 位:保留,必须为0; 
 - 
1 位: 
禁止分片(Don’t Fragment,DF)
,当 DF = 0 时才允许分片;
 - 
2 位: 
更多分片(More Fragment,MF)
,MF = 1 代表后面还有分片,MF = 0 代表已经是最后一个分片。
如果 DF 标志被设置为 1 ,但是路由要求必须进行分片,那么这条数据报回丢弃 
 - 
分片偏移(Fragment Offset)
占用 13 位,它指明了每个分片相对于原始报文开头的偏移量,以 8 字节作单位。
 - 
存活时间(Time To Live,TTL)
占用 8 位,存活时间避免报文在互联网中
迷失
,比如陷入路由环路。存活时间以秒为单位,但小于一秒的时间均向上取整到一秒。在现实中,这实际上成了一个跳数计数器:报文经过的每个路由器都将此字段减 1,当此字段等于 0 时,报文不再向下一跳传送并被丢弃,这个字段最大值是 255。
 - 
协议(Protocol)
占用 8 位,这个字段定义了报文数据区使用的协议。协议内容可以在 https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml 官网上获取。
 - 
首部校验和(Header Checksum)
占用 16 位,首部校验和会对字段进行纠错检查,在每一跳中,路由器都要重新计算出的首部检验和并与此字段进行比对,如果不一致,此报文将会被丢弃。
 - 
源地址(Source address)
占用 32 位,它是 IPv4 地址的构成条件,源地址指的是数据报的发送方
 - 
目的地址(Destination address)
占用 32 位,它是 IPv4 地址的构成条件,目标地址指的是数据报的接收方
 - 
选项(Options)
是附加字段,选项字段占用 1 - 40 个字节不等,一般会跟在目的地址之后。如果首部长度 > 5,就应该考虑选项字段。
 - 
数据
不是首部的一部分,因此并不被包含在首部检验和中。
 

IPv4 分片
最大传输单元(Maximum Transmission Unit, MTU),每个 IP 数据报封装在链路层帧中从一台路由器传到下一台路由器。因为每个链路层所支持的最大 MTU 不一样,当数据报的大小超过 MTU 后,会在链路层进行分片,每个数据报会在链路层单独封装,每个较小的片都被称为
片(fragement)。

最后一片,并且这些片会如何拼接一起成为数据报。
标识号。发送主机通常将它发送的每个数据报的标识 + 1。当某路由器需要对一个数据报分片时,形成的每个数据报具有初始数据报的源地址、目标地址和标识号。当目的地从同一发送主机收到一系列数据报时,它能够检查数据报的标识号以确定哪些数据是由源数据报发送过来的。由于 IP 是一种不可靠的服务,分片可能会在网路中丢失,鉴于这种情况,通常会把分片的最后一个比特设置为 0 ,其他分片设置为 1,同时使用偏移字段指定分片应该在数据报的哪个位置。
IPv4 寻址
- 
单播寻址模式:在这种模式下,数据只发送到一个目的地的主机。 
 

- 
广播寻址模式:在此模式下,数据包将被寻址到网段中的所有主机。这里客户端发送一个数据包,由所有服务器接收: 
 

- 
组播寻址模式:此模式是前两种模式的混合,即发送的数据包既不指向单个主机也不指定段上的所有主机 
 

IPv6

- 
版本
与 IPv4 一样,版本号由 4 bit 构成,IPv6 版本号的值为 6。
 - 
流量类型(Traffic Class)
占用 8 bit,它就相当于 IPv4 中的服务类型(Type Of Service)。
 - 
流标签(Flow Label)
占用 20 bit,这 20 比特用于标识一条数据报的流,能够对一条流中的某些数据报给出优先权,或者它能够用来对来自某些应用的数据报给出更高的优先权,只有流标签、源地址和目标地址一致时,才会被认为是一个流。
 - 
有效载荷长度(Payload Length)
占用 16 bit,这 16 比特值作为一个无符号整数,它给出了在 IPv6 数据报中跟在鼎昌 40 字节数据报首部后面的字节数量。
 - 
下一个首部(Next Header)
占用 8 bit,它用于标识数据报中的内容需要交付给哪个协议,是 TCP 协议还是 UDP 协议。
 - 
跳限制(Hop Limit)
占用 8 bit,这个字段与 IPv4 的 TTL 意思相同。数据每经过一次路由就会减 1,减到 0 则会丢弃数据。
 - 
源地址(Source Address)
占用 128 bit (8 个 16 位 ),表示发送端的 IP 地址。
 - 
目标地址(Destination Address)
占用 128 bit (8 个 16 位 ),表示接收端 IP 地址。
 
- 
标识符、标志和比特偏移:IPv6 不允许在中间路由器上进行分片和重新组装。这种操作只能在端系统上进行,IPv6 将这个功能放在端系统中,加快了网络中的转发速度。 
 - 
首部校验和:因为在运输层和数据链路执行了报文段完整性校验工作,IP 设计者大概觉得在网络层中有首部校验和比较多余,所以去掉了。IP 更多专注的是快速处理分组数据。 
 - 
选项字段:选项字段不再是标准 IP 首部的一部分了,但是它并没有消失,而是可能出现在 IPv6 的扩展首部,也就是下一个首部中。 
 
IPv6 扩展首部
扩展首部

IPv6 特点
- 
地址空间变得更大:这是 IPv6 最主要的一个特点,即支持更大的地址空间。 
 - 
精简报文结构: IPv6 要比 IPv4 精简很多,IPv4 的报文长度不固定,而且有一个不断变化的选项字段;IPv6 报文段固定,并且将选项字段,分片的字段移到了 IPv6 扩展头中,这就极大的精简了 IPv6 的报文结构。 
 - 
实现了自动配置:IPv6 支持其主机设备的状态和无状态自动配置模式。这样,没有 
DHCP 服务器
不会停止跨段通信。
 - 
层次化的网络结构:IPv6 不再像 IPv4 一样按照 A、B、C等分类来划分地址,而是通过 IANA -> RIR -> ISP 这样的顺序来分配的。IANA 是国际互联网号码分配机构,RIR 是区域互联网注册管理机构,ISP 是一些运营商(例如电信、移动、联通)。 
 - 
IPSec:IPv6 的扩展报头中有一个认证报头、封装安全净载报头,这两个报头是 IPsec 定义的。通过这两个报头网络层自己就可以实现端到端的安全,而无需像 IPv4 协议一样需要其他协议的帮助。 
 - 
支持任播:IPv6 引入了一种新的寻址方式,称为任播寻址。 
 
IPv6 地址
:号进行分隔,如果出现连续的 0 时还可以将 0 省略,并用
::两个冒号隔开,记住,一个 IP 地址只允许出现一次两个连续的冒号。
- 
二进制数表示 
 

- 
用十六进制数表示 
 

- 
出现两个冒号的情况 
 

如何从 IPv4 迁移到 IPv6
向后兼容,即 IPv6 可以收发 IPv4 的数据报,但是已经部署的具有 IPv4 能力的系统却不能够处理 IPv6 数据报。所以 IPv4 噬需迁移到 IPv6,迁移并不意味着将 IPv4 替换为 IPv6。这仅意味着同时启用 IPv6 和 IPv4。
那么现在就有一个问题了,IPv4 如何迁移到 IPv6 呢?这就是我们接下来讨论的重点。 
标志
不行的。影响不可估量不说,如何保证全球人类都能知道如何设置自己的 IPv6 地址?一个设计数十亿台机器的标志日现在是想都不敢想的。
隧道技术
隧道技术(tunneling)。
什么是隧道技术呢? 
隧道协议(tunneling protocol)。隧道协议会将这些协议的数据帧或包封装在新的包头中发送。新的包头提供了路由信息,从而使封装的负载数据能够通过互联网络进行传递。
隧道,建隧道的依据如下:

数据(有效载荷)字段中,于是,IPv4 数据报的地址被设置为指向隧道接收端的 IPv6 的节点,比如上面的 E 节点。然后再发送给隧道中的第一个节点 C,如下所示

总结
本文分享自微信公众号 - Java后端(web_resource)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
