协议森林4——我尽力:IP协议详解

上两篇“IP 接力”和“IP 地址”,让我们了解了 IP 协议的基本工作方式。我们在这一篇中回归 IP 协议本身,看一看 IP 协议的具体细节和设计哲学。
IPv4 与 IPv6 头部的对比
我们已经在 IP 接力中介绍过,IP 协议把数据包裹进一个个数据包。每个 IP 包分为头部(header)和数据(payload/data)两部分。和其他网络传输协议一样,头部携带的是实现通信必须的附加信息。数据部分才是通信真正要传送的信息。IP 协议规定了一个 IP 包头部的格式。下图是 IPv4 和 IPv6 的头部,我们来研究一下两者的异同。
协议森林4——我尽力:IP协议详解_第1张图片
黄色区域:相同区域
我们看到,有三个黄色区域同时存在于 IPv4 和 IPv6。版本号(Version)占了 4 位的长度,用来表明 IP 协议版本,是 IPv4 还是 IPv6。对于 IPv4 来说, 它的四位版本号是 0100,即二进制的 4。IPv6 的四位版本号为 0110。出发地址(Source Adrresss)和目的地址(Destination Address)分别为发出地和目的地的 IP 地址。
蓝色区域:名字更改区域
传输上限

在 IPv4 中有存活时间(Time to Live),对应 IPv6 中的最大中继数(Hop Limit)。存活时间最初是表示一个 IP 包的最大存活时间:如果 IP 包在传输过程中超过存活时间,那么 IP 包就作废。后来,IPv4 的这个区域记录一个整数。比如整数 30,就表示在 IP 包接力过程中最多经过 30 个路由接力,如果超过 30 个路由接力,那么这个 IP 包就作废。IP 包每经过一个路由器,路由器就给存活时间减一。当一个路由器发现存活时间为 0 时,就不再发送该 IP 包。IPv6 中的最大中继数记录直接就是最大路由接力数。两者不同名,但有相同功能,都避免了 IP 包在互联网中无限接力。
服务/交通类型
IPv4 中的服务类型(Type of Service)最初是用来给 IP 包分优先级,比如语音通话需要实时性,所以它的 IP 包应该比 Web 服务的 IP 包有更高的优先级。然而,这个最初不错的想法没有被微软采纳。在 Windows 下生成的 IP 包都是相同的最高优先级,所以在当时造成 Linux 和 Windows 混合网络中,Linux 的 IP 传输会慢于 Windows。说来荒唐的是,慢的原因仅仅是因为 Linux 更加守规矩。后来,服务类型被实际分为两部分:服务区分(Differentiated Service Field, 即 DS,前 6 位)和外部阻塞通知(Explicit Congestion Notification,即 ECN,后 2 位),前者依然用来区分服务类型,而后者用于表明 IP 包途径路由的交通状况。IPv6 的交通类型(Traffic Class)与 IPv4 的服务类型相似,结构上也被如此分成两部分。通过 IP 包提供不同服务的想法,并针对服务进行不同的优化的想法已经产生很久了,但具体做法并没有形成公认的协议。比如 ECN 区域,它用来表示 IP 包经过路径的交通状况。如果接收者收到的 ECN 区域显示路径上的很拥挤,那么接收者应该作出调整。但在实际上,许多接收者都会忽视 ECN 所包含的信息。交通状况的控制往往由更高层的比如 TCP 协议实现。
协议森林4——我尽力:IP协议详解_第2张图片
碎片
高层协议
IPv4 中的协议,也就是 IPv6 中的内层格式(Next Header)。它们都用来说明 IP 包 Payload 部分所遵循的协议,也就是 IP 包的数据部分使用的更高层协议是什么。它说明了 IP 包封装的是一个怎样的高层协议包,比如说 TCP 协议或者 UDP 协议。
长度信息
IPv4 中的总长(Total Length), 以及 IPv6 中数据长度(Payload Length)。它们都用来记录 IP 包的大小。IPv4 中的总长是整个数据包的长度。而 IPv6 的数据长度只记录了数据部分的大小。但 IPv6 的头部是固定的长度 40 字节,所整个 IP 包的总长就是 40 字节加上数据长度。
红色区域 (IPv6 中删除的区域)
IPv4 包在头部的最后,可以有多个选项(options)。每个选项有 32 位。选项不是必须的,所以一个 IPv4 头部可以完全没有选项。不考虑选项的话,整个 IPv4 头部有 20 字节。但由于有选项的存在,整个头部的总长度是浮动的。我们用头部总长(IHL,Internet Header Length)来记录头部的总长度。通过头部总长,我们能知道哪些部分是选项。IPv6 没有选项。它的头部是固定的长度 40 字节,所以 IPv6 中并不需要记录头部总长。
IPv4 中还有一个头部校验码(Header Checksum)区域。这个校验码用于校验 IP 包的头部信息。我们在介绍以太网的“小喇叭”一文中也见过校验码,但 IP 校验码所使用的算法与以太网的 CRC 算法不同。IPv6 没有校验相关的区域。IPv6 包的校验依赖高层的协议来完成,因此免去了执行校验时间,减小了网络延迟 。
身份(Identification),标识(flags)和碎片补偿(fragment offset),这三个包都是为碎片化(fragmentation)服务的。碎片化是指一个路由器将接收到的 IP 包分拆成多个 IP 包传送,而接收这些“碎片”的路由器或者主机需要将“碎片”重新组合(reassembly)成一个 IP 包。不同的局域网所支持的最大传输单元(MTU, Maximum Transportation Unit)不同。如果一个 IP 包的大小超过了局域网支持的 MTU,就需要在进入该局域网时碎片化传输。这就好像方面面面饼太大了,必须掰碎才能放进碗里。碎片化会给路由器和网络带来很大的负担。最好在 IP 包发出之前探测整个路径上的最小 MTU,IP 包的大小不超过该最小 MTU,就可以避免碎片化。IPv6 在设计上避免碎片化。每一个 IPv6 局域网的 MTU 都必须大于等于 1280 字节。IPv6 的默认发送 IP 包大小为 1280 字节。
绿色区域 (IPv6 新增区域)
流标签(Flow Label)是 IPv6 中新增的区域。它被用来提醒路由器来重复使用之前的接力路径。这样 IP 包可以自动保持出发时的顺序。这对于流媒体之类的应用有帮助。流标签的进一步应用尚在开发中。
“我尽力”
IP 协议在产生时是一个松散的网络,这个网络由各个大学的局域网相互连接成的,由一群碰头垢面的 Geek 维护。所以,IP 协议认为自己所处的环境是不可靠的:诸如路由器坏掉、实验室失火、某个 PhD 踢掉电缆之类的事情随时会发生。
这样的凶险环境下,IP 协议提供的传送只能是“我尽力”(best effort)式的。所谓的“我尽力”,其潜台词是,如果事情出错不要怪我,我只是答应了尽力,可没保证什么。所以,IP 包传输过程中可能出现各种各样的错误,比如校验码对不上、交通太繁忙、比如超过最大存活时间,根据 IP 协议,你的 IP 包会直接被丢掉。就是这样……被丢掉了……不会再有进一步的努力来修正错误。“我尽力”原则让 IP 协议保持很简单的形态。更多的质量控制交给高层协议处理,IP 协议只负责有效率的传输。
“效率优先”也体现在 IP 包的顺序上。即使出发地和目的地保持不变,IP 协议也不保证 IP 包到达的先后顺序。我们已经知道,IP 接力是根据路由表决定接力路线的。如果在连续的 IP 包发送过程中,路由表有时会更新,比如有一条新建的捷径出现。这种时候,后发出的 IP 包选择走不一样的接力路线。如果新的路径传输速度更快,那么后发出的 IP 包有可能先到。这就好像是多车道的公路上,每辆车都在不停变换车道,最终所有的车道都塞满汽车。这样可以让公路利用率达到最大。
IPv6 中的流标签可以建议路由器将一些 IP 包保持一样的接力路径。但这只是“建议”,路由器可能会忽略该建议。
IPv4 的校验算法
IPv4 会校验头部信息。校验码区域有 16 位。这个校验码是这样获得的。首先,从头部取得除校验码之外的信息,例如下面是一个演示的头部,写成十六进制形式:

9194 8073 0000 4000 4011 C0A8 0001 C0A8 00C7

信息按照 16 位分割,也就是每 4 位 16 进制数分为一组。上面的序列已经分割好了。将分割后的各个 4 位 16 进制数累积相加。如果有超过 16 位的进位出现,则将进位加到后 16 位结果的最后一位。比如说先将最开始的两组 16 进制数求和,获得:

9194 + 8073 = 1 1207

结果是 11207,从 4 位变成了 5 位。那么将进位的 1 加到 1207 上:

1207 + 1 = 1208

上面的求得 1208 的过程就叫做叫做一补数求和(one’s complement sum)。用 1208 继续累加,直到获得所有组的累积和,将会是 1433。
然后,将十六进制的 1433 写成二进制序列,把二进制的每一位取,即 0 变成 1、 1 变成 0, 就得到校验码:EBCC。把校验码 EBCC 插回到头部,我们整个头部就是:

9194 8073 0000 4000 4011 EBCC C0A8 0001 C0A8 00C7

IP 包的接收方在接收到 IP 包之后,对整个头部进行一次一补数累积和运算,应该得到 FFFF。如果不是 FFFF,那么传输过程中,头部信息发生变动,造成校验码与头部信息对不上。根据“我尽力”原则,整个 IP 包会被丢弃。
总结
每个网络协议的形成都有其历史原因。比如 IP 协议是为了将各个分散的实验室网络连接起来。由于当时的网络很小,所以 IPv4 的地址总量为 40 亿。尽管当时被认为是很大的数字,但数字浪潮很快带来了地址耗尽危机。IPv6 的主要目的是增加 IPv4 的地址容量,但同时根据 IPv4 的经验和新时代的技术进步进行改进,比如避免碎片化以及取消验证码。网络协议技术上并不复杂,更多的考量是政策性的。
IP 协议是“我尽力”式的,IP 传输是不可靠的。但这样的设计成就了 IP 协议的效率。

你可能感兴趣的:(协议森林4——我尽力:IP协议详解)