基础
在网络通信中,网络层只负责将数据发送到对应的主机,不保证一定送达,发送过程中可能会出现的数据丢失、网络拥堵等问题都是由传输层处理的。网络层的核心协议就是IP协议。
由于需要将数据送到一个确定的主机,IP协议需要在网络中标识主机的唯一性,因此每台主机必须设置IP地址。如图所示,主机B发送数据到主机C时,会由多个路由器依次传递,最终传递到主机C,在这个过程中,各个路由器就是通过IP地址来确定下一步要将数据交给哪个路由器的。

在网络还没有普及的时候,一般都是一些大学、公司的科研机构在使用网络,主要用于机构内部通信,没有在机构间相互连接,是一种私有网络。彼时的网络是分散的,各自覆盖某一个小地区。这种只限制在某一个小地区的网络被称为局域网。后来要建立全球化的网络时,就是在各个地区的建立相互连接的局域网,组成一个小范围的网络,然后连接起来。
当然,由于这种局域网技术最初就是用于机构内部的通信,覆盖范围有限,只是单纯的将各个局域网连接起来肯定不行,远距离通信时数据会经过很多局域网,路径选择复杂。因此网络在逻辑上被设计为层状结构,就像我们设置行政中心一样,将同一地区的局域网连接到一个大型路由器上,这个大型路由器与其它地区的大型路由器建立连接,形成一个覆盖大范围的大型网络。这个大型网络与一个层级更高的路由器连接,这个高层级的路由器再与其它的高层级路由器连接,形成一个范围更大的网络,以此类推,最终就建立起了一个覆盖全球的网络。值得一提的是,路由器并没有严格的等级制度,高层级的路由器也可能会与层级较低的路由器连接。
子网
子网概念
从物理层面上看,网络是由各个路由器相互连接形成的统一整体,但从逻辑上,为了方便管理,网络被分为无数个相互连接的子网。同一个子网内的主机或路由器可以直接通信,不需要通过其它路由器中转。子网是一个抽象的概念,它可以很大,跨越多个局域网(借助VPN、VLAN Trunk等技术),也可以很小,仅包含由一根网线连接的两台设备。同时,子网也和路由器一样,有不同的层级,不同层级的子网由不同层级的路由器维护。先简单了解即可,后面展开。
子网掩码
回到网络层的IP协议,使用网络通信需要通过IP地址唯一标识网络中的,IP地址分为两部分,前面一部分是网络号 ,用于将数据送到目标主机所在的子网。剩下的部分是主机号 ,用于在目标子网中找到目标主机。

过去曾经提出一种划分网络号和主机号的方案, 把所有 IP 地址分为五类, 如下图所示。可以看到每一类的IP地址由于开头的几位各不相同,所以可以相互区分。

不同的类别的IP地址中,主机号所占部分大小不同,一个子网内的主机越多,就应该使用主机号占比越大的IP种类,以确保能给每一个主机分配一个IP。
随着网络的飞速发展,这种划分方案的局限性很快显现出来。例如B类地址,理论上能允许一个子网内存在6万5千多个主机,A类地址的子网内的主机数更多。然而实际网络架设中,不会存在一个子网内有这么多主机的情况。大多数组织都申请B类网络地址,导致B类地址很快就分配完了,而A类却没用多少,因此大量的IP地址都被浪费掉了。
针对这种情况提出了新的划分方案,称为CIDR (Classless Interdomain Routing),它引入一个额外的子网掩码 (subnet mask)来区分网络号和主机号。子网掩码也是一个32位的正整数,前面全是"1"后面全是"0" ;将IP地址和子网掩码进行按位与 操作,得到的结果就是网络号,相当于取出IP地址的前面一部分,后面全为0,然后将其作为网络号。这样一来,网络号和主机号的划分与这个IP地址是A类、B类还是C类无关。如下。

此时IP地址由于主机号全0表示的是网络号 ,主机号全1 不能分配,只能作为报文目的IP地址,表示该报文是广播,所有主机都要处理。因此子网内能存在的主机数就是主机号能表示的总数减2,即主机号最大值减1。
子网划分本质
就像我们将地址按照省、市、县等不同等级划分一样,网络也被划分为不同层级的子网,而在同一个网络下,IP的网络号开头是相同的。我们以地址类比,在福建省内的所有市的地址,都是以"福建省"开头,而在福建省的厦门市内的所有县区的地址都是以"福建省厦门市"开头,以此类推。
在网络中也是类似,由不同层级路由器维护的不同层级的子网,其网络号的"开头"(即网络前缀)会逐级保持一致。例如,一个省级网络可能占用网络号11.0.0.0/8,则该网内所有IP地址的前8位(对应11.开头)都是相同的;从中划分出市级子网 11.1.0.0/16,则这个子网内的地址前16位(对应11.1.开头)都相同,并且包含省级的10.前缀。
当一份报文从上层网络的路由器往下传递时,各个层次的路由器就是通过前面提到的子网掩码来提取网络号的信息,不同层次的子网使用不同长度的掩码(例如/8、/16、/24),就能提取不同层次的网络号,进而确定发给哪个下层子网的路由器。简单来看,网络就是一个树状结构。

上面这些是在理想情况下才成立,网络并不是由某一个机构单独管理的。每个机构都会以自己的方式规划、搭建自己的网络,例如电信、移动、联通都搭建了自己的网络。当然,不同机构的网络会在最顶层相互连接,但是网络内部由自己管理。这种由机构自己搭建、由机构自己管理的网络被称为自治系统(Autonomous System)。所以,整体上看,网络是由大大小小的自治系统相互连接而成,每个自治系统都有自己的树状网络。如下

如果电信网络内的一个主机想要向联通网络内的一个主机发送数据,就需要先发送到电信网络顶层的路由器(骨干路由器),由骨干路由器转发给联通网络的骨干路由器,再由后者向下转发,即使这两台主机离得很近。当然,运营商的骨干路由器有很多个,每个省至少都有一台,每台都可以作为运营商自治系统的出入口。
这些骨干路由器会在当地维护当地的树状网络,如果有数据要跨省传输,也需要它们来转发。所以,上面的简图中,每个运营商内部只有一个树状网络,但其实应该有许多在顶层相互连接的树状网络。
那么,机构对自己的自治系统进行子网划分的大致过程就是,机构申请适量的IP地址,设置子网掩码进行多级划分,根据具体的硬件设备连接情况和拓扑结构分配IP地址(要满足同一个子网内的设备通信时无需经过路由器)。
公网与NAT
公网IP与私有IP
公网(Internet)就是互联网,由全球范围内所有互联的自治系统共同构成的网络集合。

如果一台主机要在公网上通信,需要能够在公网上唯一标识自己的IP地址,但是如果给全球所有的主机都分配一个唯一的IP地址,那IP地址又有些不够用。所以一般是给局域网的路由器分配一个公网IP(WAN口IP),在该路由器组建的局域网内,主机使用可以重复的私有IP。需要公网通信时,由局域网路由器将主机发来的报文中,源IP(主机的私有IP)换成路由器自己的公网IP,并记录下来,收到应答时再通过记录确定是发给哪个私有IP,这就是NAT(网络地址转换)。
RFC 1918规定了用于组建局域网的私有IP地址:
10.*,前8位是网络号,共16,777,216个地址;
172.16.* 到 172.31.* ,前12位是网络号,共1048576个地址;
192.168.*,前16位是网络号,共65,536个地址。
包含在这个范围中的都称为私有IP,其余的则称为全局IP(公网IP)。不同局域网内的主机可能使用相同的私有IP,因此私有IP不能在公网上使用。需要补充一点的是,局域网路由器也会给自己增设一个私有IP(LAN口IP),用于局域网内部的通信,以便于内部管理。
尽管如此,IP地址仍然有些不够用,所以,除了我们家里的局域网路由器会使用NAT,运营商也会在市级或更低级网络的出口使用NAT,让网络内部的绝大部分局域网路由器也使用运营商分配的私有IP,进一步节省公网IP地址。
NAT转换表
路由器在进行NAT(网络地址转换)时,会将转换前后的映射关系记录在内部的转换表(NAPT表)中。如果两个不同的源IP访问同一个IP的同一个端口号,那么路由器除了将报文的源IP转换为路由器的WAN口IP,还会转换端口号,以便收到应答时,能够根据端口号区分不同的主机,并完成应答报文的目的IP、目的端口的转换。如下图。

可以发现,当客户端访问服务器时,服务器能够将应答发送回客户端的关键是途经的路由器中,转换表有转换目的IP、目的端口号的映射,而这个映射必须在客户端向服务器发送请求时生成,因此,服务器永远无法先手向客户端发送报文。
路由
我们知道,数据通过网络传输,需要由多个路由器依次转发,数据在网络中就像下图这样在各个路由器节点上一跳一跳向前传输。在这个过程中,收到数据的路由器需要两个操作,一是确认数据下一跳的地址,即要将数据发给哪个路由器,二是将数据发送过去,这个确认下一跳地址的操作就是路由。

确认数据要发给哪个路由器的关键是路由表。路由表中记录了路由器连接的其它路由器维护的子网的网络号,以及对应路由器的IP地址,如下图。由于其它路由器维护的子网的层级可能不同,对应的网络号长度不同,因此路由表还记录了各个网络号对应的子网掩码(下图的Genmask)。
当路由器收到数据时,通过子网掩码与数据的目的IP地址按位与,从而提取对应长度的网络号,并进行比对。由于从目的IP提取的长度不同,可能有多个子网都能匹配,这些匹配的子网中,网络号最长的那个子网会被选中,路由器会通过路由表中记录的下一条地址将数据发送给对应的路由器。

另外,如果数据的目的IP就在路由器维护的子网内,比如收到数据的就是目标主机所在的局域网的路由器,那么路由器会直接将数据通过ARP(介于网络层与数据链路层之间的协议)发送给目标主机。
IP协议报文
各字段大致用法
IP协议的报文如图所示

IP协议的报头同样带有选项,解包要分离有效载荷时,会先读取前20字节,从首部长度字段中读取报头总长度,并据此读取出选项即可分离有效载荷。以下是各个字段的用法,上图第二行和分片有关,后面会讲。
8位协议 : 表示的是上层使用的是哪个传输层协议(TCP/UDP)
8位服务类型(Type Of Service):3位优先权字段(已经弃用),4位TOS字段,和1位保留字段(必须置为0)。4位TOS分别表示:最小延时,最大吞吐量,最高可靠性,最小成本。这四者相互冲突,只能选择一个。对于ssh/telnet这样的应用程序,最小延时比较重要;对于ftp这样的程序,最大吞吐量比较重要。
8位生存时间(Time To Live,TTL):数据报到达目的地的最大报文跳数,一般是64。每次经过一个路由,TTL减1,一直减到0还没到达,那么就丢弃了。这个字段主要是用来防止出现路由循环,即报文在几个路由器之间不断循环转发。
16位头部校验和:用来鉴别报头是否损坏。
分片
要交给数据链路层发送的报文不能超过最大传输单元(MTU),默认为1500字节。如果超过了,就需要对在网络层对数据进行分片,即将数据分成多个分片,然后才能交给数据链路层发送。一个分片是一个IP报文,全部送达目标主机后,这些分片同样需要在网络层进行组装。
而IP协议不会处理数据丢失的问题,任何一个分片丢失,都表示该报文整体丢失。因此,如果对数据分片,就会导致丢包概率增加。
为此,传输层协议每次向IP协议交付的报文长度不宜超过1480字节(标准IP报头占20字节)。对于TCP协议而言,每次从发送缓冲区取出的要发送的数据大小不宜超过1460字节,而这1460字节就是最大段尺寸(MSS)
在下图的IP协议的报头中,第二行就用于分片和组装。

16位标识用于区分不同份的数据,属于同一份数据的分片,其标识相同,反之则不同。
3位标志字段:第一位保留(保留的意思是现在不用,但是还没想好,说不定以后要用到);第二位设为1表示禁止分片,这时候如果报文长度超过MTU,该报文就会直接被丢弃;第三位表示"更多分片",如果分片了的话,最后一个分片置为0,其它位置分片置为1,类似于一个结束标记。
13位片偏移字段用于表示该分片的数据在原来完整数据中的偏移量,用于重新组装数据。
将三个字段组合起来使用,就能完成分片和组装。