协议森林05 我尽力 (IP协议详解)

作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁任何形式转载。

在粗略了解了IP接力IP地址后,我们再反过来,看一看IP协议的具体细节和设计哲学。

IPv4与IPv6头部的对比

我们已经在IP接力中介绍过,一个IP包分为头部(header)和数据(payload/data)两部分。头部是为了实现IP通信必须的附加信息,数据是IP通信所要传送的信息。

黄色区域 (同名区域)

我们看到,三个黄色区域跨越了IPv4和IPv6。Version(4位)用来表明IP协议版本,是IPv4还是IPv6(IPv4, Version=0100; IPv6, Version=0110)。Source Adrresss和Destination Address分别为发出地和目的地的IP接力

蓝色区域 (名字发生变动的区域)

Time to Live 存活时间(Hop Limit in IPv6)。Time to Live最初是表示一个IP包的最大存活时间:如果IP包在传输过程中超过Time to Live,那么IP包就作废。后来,IPv4的这个区域记录一个整数(比如30),表示在IP包接力过程中最多经过30个路由接力,如果超过30个路由接力,那么这个IP包就作废。IP包每经过一个路由器,路由器就给Time to Live减一。当一个路由器发现Time to Live为0时,就不再发送该IP包。IPv6中的Hop Limit区域记录的也是最大路由接力数,与IPv4的功能相同。Time to Live/Hop Limit避免了IP包在互联网中无限接力。

Type of Service 服务类型(Traffic Class in IPv6)。Type of Service最初是用来给IP包分优先级,比如语音通话需要实时性,所以它的IP包应该比Web服务的IP包有更高的优先级。然而,这个最初不错的想法没有被微软采纳。在Windows下生成的IP包都是相同的最高优先级,所以在当时造成Linux和Windows混合网络中,Linux的IP传输会慢于Windows (仅仅是因为Linux更加守规矩!)。后来,Type of Service被实际分为两部分:Differentiated Service Field (DS, 前6位)和Explicit Congestion Notification (ECN, 后2位),前者依然用来区分服务类型,而后者用于表明IP包途径路由的交通状况。IPv6的Traffic Class也被如此分成两部分。通过IP包提供不同服务的想法,并针对服务进行不同的优化的想法已经产生很久了,但具体做法并没有形成公认的协议。比如ECN区域,它用来表示IP包经过路径的交通状况。如果接收者收到的ECN区域显示路径上的很拥挤,那么接收者应该作出调整。但在实际上,许多接收者都会忽视ECN所包含的信息。交通状况的控制往往由更高层的比如TCP协议实现。

Protocol 协议(Next Header in IPv6)。Protocol用来说明IP包Payload部分所遵循的协议,也就是IP包之上的协议是什么。它说明了IP包封装的是一个怎样的高层协议包(TCP? UDP?)。

Total Length, 以及IPv6中Payload Length的讨论要和IHL区域放在一起,我们即将讨论。

红色区域 (IPv6中删除的区域)

我们看一下IPv4和IPv6的长度信息。IPv4头部的长度。在头部的最后,是options。每个options有32位,是选填性质的区域。一个IPv4头部可以完全没有options区域。不考虑options的话,整个IPv4头部有20 bytes(上面每行为4 bytes)。但由于有options的存在,整个头部的总长度是变动的。我们用IHL(Internet Header Length)来记录头部的总长度,用Total Length记录整个IP包的长度。IPv6没有options,它的头部是固定的长度40 bytes,所以IPv6中并不需要IHL区域。Payload Length用来表示IPv6的数据部分的长度。整个IP包为40 bytes + Payload Length。

IPv4中还有一个Header Checksum区域。这个checksum用于校验IP包的头部信息。Checksum与之前在小喇叭中提到的CRC算法并不相同。IPv6则没有checksum区域。IPv6包的校验依赖高层的协议来完成,这样的好处是免去了执行checksum校验所需要的时间,减小了网络延迟 (latency)。

Identification, flags和fragment offset,这三个包都是为碎片化(fragmentation)服务的。碎片化是指一个路由器将接收到的IP包分拆成多个IP包传送,而接收这些“碎片”的路由器或者主机需要将“碎片”重新组合(reassembly)成一个IP包。不同的局域网所支持的最大传输单元(MTU, Maximum Transportation Unit)不同。如果一个IP包的大小超过了局域网支持的MTU,就需要在进入该局域网时碎片化传输(就好像方面面面饼太大了,必须掰碎才能放进碗里)。碎片化会给路由器和网络带来很大的负担。最好在IP包发出之前探测整个路径上的最小MTU,IP包的大小不超过该最小MTU,就可以避免碎片化。IPv6在设计上避免碎片化。每一个IPv6局域网的MTU都必须大于等于1280 bytes。IPv6的默认发送IP包大小为1280 bytes。

令人痛苦的碎片化

绿色区域 (IPv6新增区域)

Flow Label是IPv6中新增的区域。它被用来提醒路由器来重复使用之前的接力路径。这样IP包可以自动保持出发时的顺序。这对于流媒体之类的应用有帮助。Flow label的进一步使用还在开发中。

“我尽力”

IP协议在产生时是一个松散的网络,这个网络由各个大学的局域网相互连接成的,由一群碰头垢面的Geek维护。所以,IP协议认为自己所处的环境是不可靠(unreliable)的:诸如路由器坏掉、实验室失火、某个PhD踢掉电缆之类的事情随时会发生。

不靠谱的网络

这样的凶险环境下,IP协议提供的传送只能是“我尽力” (best effort)式的。所谓的“我尽力”,其潜台词是,如果事情出错不要怪我,我只是答应了尽力,可没保证什么。所以,如果IP包传输过程中出现错误(比如checksum对不上,比如交通太繁忙,比如超过Time to Live),根据IP协议,你的IP包会直接被丢掉。Game Over, 不会再有进一步的努力来修正错误。Best effort让IP协议保持很简单的形态。更多的质量控制交给高层协议处理,IP协议只负责有效率的传输。

(多么不负责任的邮递系统)

“效率优先”也体现在IP包的顺序(order)上。即使出发地和目的地保持不变,IP协议也不保证IP包到达的先后顺序。我们已经知道,IP接力是根据routing table决定接力路线的。如果在连续的IP包发送过程中,routing table更新(比如有一条新建的捷径出现),那么后发出的IP包选择走不一样的接力路线。如果新的路径传输速度更快,那么后发出的IP包有可能先到。这就好像是多车道的公路上,每辆车都在不停变换车道,最终所有的车道都塞满汽车。这样可以让公路利用率达到最大。

“插队”

IPv6中的Flow Label可以建议路由器将一些IP包保持一样的接力路径。但这只是“建议”,路由器可能会忽略该建议。

Header Checksum算法

Header Checksum区域有16位。它是这样获得的,从header取得除checksum之外的0/1序列,比如:

9194 8073 0000 4000 4011 C0A8 0001 C0A8 00C7 (十六进制hex, 这是一个为演示运算过程而设计的header)

按照十六位(也就是4位hex)分割整个序列。将分割后的各个4位hex累积相加。如果有超过16位的进位出现,则将进位加到后16位结果的最后一位:

  Binary                Hex

  1001000110010100      9194

+ 1000000001110011      8073

  ----------------

1 0001001000000111     11207

+                1

  ----------------

  0001001000001000      1208 上面的计算叫做one's complement sum。求得所有十六位数的和,

one's complement sum(4500, 0073, 0000, 4000, 4011, C0A8, 0001, C0A8, 00C7) = 1433

然后,将1433的每一位取反(0->1, 1->0), 就得到checksum:EBCC

这样,我们的header就是:

9194 8073 0000 4000 4011 EBCC C0A8 0001 C0A8 00C7

IP包的接收方在接收到IP包之后,可以求上面各个16位数的one's complement sum,应该得到FFFF。如果不是FFFF,那么header是不正确的,整个IP包会被丢弃。

(再次提醒,示例所用的IP header不是真实的header,它只是起演示算法的作用)

总结

每个网络协议的形成都有其历史原因。比如IP协议是为了将各个分散的实验室网络连接起来。由于当时的网络很小,所以IPv4(IPv4产生与70年代)的地址总量为40亿。尽管当时被认为是很大的数字,但数字浪潮很快带来了地址耗尽危机。IPv6的主要目的是增加IPv4的地址容量,但同时根据IPv4的经验和新时代的技术进步进行改进,比如避免碎片化,比如取消checksum (由于高层协议TCP的广泛使用)。网络协议技术上并不复杂,更多的考量是政策性的。

IP协议是"Best Effort"式的,IP传输是不可靠的。但这样的设计成就了IP协议的效率。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏王金龙的专栏

编程语言中那些有趣的命名

      学习NodeJS的时候,一定会用到其包管理器npm。npm的字面意思是node package manager,实际的含义也是这样,但是npm真正的...

1472
来自专栏张善友的专栏

Entity Framework Code First 支持存储过程

存储过程(Stored Procedure)不仅仅是将多得简直荒唐的业务逻辑塞入数据库的一种方式;它还是避免将多得简直荒唐的存储逻辑塞入应用程序层(applic...

2058
来自专栏FreeBuf

Bash漏洞再次演进:缓冲区溢出导致远程任意命令执行

近几天,“Shellshock”Bash漏洞的出现可谓是给安全界投放了一颗重型炸弹,越来越多的厂商和黑白帽子都纷纷加入到分析阵营当中,同时也接二连三爆出了更多针...

21310
来自专栏一个会写诗的程序员的博客

《Kotlin极简教程》第1章 Kotlin简介

我们这里讲的Kotlin,就是一门以这个Котлин岛命名的现代程序设计语言。它是一门静态类型编程语言,支持JVM平台,Android平台,浏览器JS运行环境,...

962
来自专栏积累沉淀

linux学习之硬盘的存储原理和内部架构

首先,让我们看一下硬盘的发展史: 1956年9月13日,IBM的IBM 350 RAMAC(Random Access Method of Accounting...

3976
来自专栏静晴轩

Rake让Jekyll写博更优雅

于想拥有个人站点品牌的人来讲,现如今是一个很好的时期。至少 Hexo、Jekyll、Leanote、WordPress 、FarBox Octopress、gh...

3925
来自专栏FreeBuf

从Android短信漏洞到手机钓鱼木马

本文所涉及的技术和代码仅供研究之用,严禁将之用于非法用途,如有违反,所引发的一切后果与本人无关! 认识刘尼玛   在一个阳光明媚的早晨,小职员刘尼玛像往常一样...

2686
来自专栏哲学驱动设计

CQRS讨论

今天和同事一起讨论了CQRS(Command Query Responsibility Segregation),过程中,我产生了一些疑问,先记录在这里,以后有...

1887
来自专栏北京马哥教育

余生只够写50行代码,这么写绝对赚翻了

学Python最简单的方法是什么?推荐阅读:Python开发工程师成长魔法 假如有一天死神来找你,警告你最多只能再写50行代码,然后就得随他而去,应该写点什么...

3278
来自专栏SAP最佳业务实践

SAP最佳业务实践:FI–现金管理(160)-14银企对账-客户收款-承兑汇票-F-36收到承兑汇票

4.5.2 F-36收到银行承兑汇票 收到客户银行承兑汇票支付应收账款,形成财务记账如下: 借:应收票据 贷:应收账款 ? 输入凭证日期、参照、抬头文本 回...

3158

扫码关注云+社区

领取腾讯云代金券