网络层
—
IP 协议属于网络协议栈的网络层。这一层的功能目标是将数据包从网络的一个位置传送到另一个位置,算是处理端到端传输的最底层。传输过程中间会经过许多跳(hop)中间路由器,因此路由算法是其设计的核心任务。(但很可惜不是本篇的核心任务)
隧道
—
当两个相同的网络被一个不同的网络隔开时,隧道就是一种跨协议通信的便利方法。即把 A 网络的数据包整个包成一个 B 网络的数据包,然后在 B 网络中传输,到达目的地后再取出来得到一个 A 网络数据包。
这种构建于基础网络上的一个新网络就称为覆盖(overlay),这是逐步部署新型网络的一个有效方法,比如在 IPv4 上构建 IPv6 网络。
IPv4
—
IPv4 的头就是下图这个样子,具体每个字段的作用就不说了。
值得注意的是它的源地址和目标地址的长度是 32 位,现在大家都知道这个长度不够用了。而其实 IP 地址在分配效率上也有问题,以至于实际情况比理论上更糟。
子网
因为 IP 协议主要解决的问题是网络间互联,以及考虑到网络间路由的复杂性。把 IP 地址分层是一种较好的处理方法。即一个 32 位的 IP 地址,有前 N 位来标识一个网络(子网),后 32-N 位来标识属于这个网络内的主机。这样路由器在转发数据包时,只考虑 N 位前缀就可以了,这样能大幅减少路由表的大小。想象一下 8.8.8.8
和 8.8.8.7
如果一个在美国一个在中国那路由器都要疯了。
而且这个 N 的值还可以是动态的,这个 N 的写法可以写作 /16
表示前 16 位是网络段,后 16 位是主机段。更一般的写法是写成 32 位的子网掩码的格式。比如 /16
等于 255.255.0.0
的子网掩码。
可以看出子网掩码造成了一种复用 IP 地址的可能性。即对于同一个 IP 地址,不同的子网掩码可以标记不同的网络端点。但因为子网掩码只是路由协议的一部分(可以看上面的 IP 头,并不含有子网掩码),以及其可能比简单增加 IP 地址位数带来更大的复杂性(我没算,猜的),这种复用技术并没有被用来增加公网上的可用 IP 地址。
分类寻址(classful addressing) 和 CIDR
很多人可能听说过公网 IP 地址有 A、B、C 三类之分。这其实就是子网按不同大小前缀划分的一种方法。如下图:
可以看到这种划分方式的主要缺点是网络地址和主机地址的划分太不合理了,对多数组织机构而言,B 类地址太大而 C 类太小(包含的主机数太少)。因此 CIDR - classless inter domain routing 无类域间路由被实际使用着。因为又回到了路由算法的范畴,这里略过。
NAT
那么这么少的公网 IP 到底是如何支撑起现在这么多的上网用户的呢?很多人可能想到了答案就在家里的路由器上。因为造成实际网络开放的就是它。
Network Address Translation 网络地址转换就是干这事的。这个功能存在于每个家用路由器里,他负责把用户数据包的 IP 地址从内网 IP 如(192.168.1.101)转换为一个合法的公网 IP,通过篡改 IP 数据包的方式。
这里的主要问题是,因为内网 IP 和 外网 IP 是个 多对一
的关系,所以转过去容易,转回来难。那么路由器在接收到来自外网的数据包时,如何决定把包头替换成哪个内网 IP 呢?答案是一个比较糟糕的方法。因为网络层的更上一层 - 传输层的两种主流协议,TCP 和 UDP 占据了传输层绝大部分流量,而这两种协议的头都具有一个标识源端口和目标端口的字段(用以标记连接对象的具体进程,或者说端口)。然后 NAT 就把这个端口号给替换掉了,换成了自己一个映射表里的键。然后在接收到外网数据包时,再通过这个数据包里的 TCP 端口号在映射表里查询到内网主机的 IP 和 真正 TCP 端口号,并替换回来。
显然这样做违反了网络协议栈的分层原则,并且依赖于传输层必须使用某些协议。但在 IPv6 普及之前,NAT 工作的效果还算好。
这种依赖很可能也是 TCP/IP 总被放在一起的原因。
IPv6
—
简单说,IPv6 和 IPv4 和区别在于拥有一个 128 位的地址,以及去掉了校验和,以及其他。
因为隧道的使用,IPv6 在部署上可以非常灵活,按需配置。因此 IPv6 普及的关键可能在于特定需求得到市场的广泛认可。