A contented mind is a perpetual feast.
"知足长乐"
参考资料:TCP/IP入门经典 (第五版)
一、简介
IP(Internet Protocol,网际协议),是TCP/IP协议族中最核心的协议,位于协议栈的网络层
既然位于网络层,所以IP最主要的功能就是 提供独立于硬件的逻辑寻址 和 支持网间数据传递的路由选择,我们将在后面的部分介绍这两个功能,下面先来分析一下IP首部
二、IP首部
我们在 TCP/IP-入门 中说到:当传输层的TCP分段或UDP数据报传送到网络层时,IP将会为分段或数据报封装上IP首部,接下来我们分析一下IP首部,IP数据报格式如下
其中各字段的含义如下:
● 4位版本:目前的协议版本号是4,即IPv4
● 4位首部长度:我们注意到上图中每一行的长度是32 bit,即4个字节,首部长度指的就是首部占32 bit的数目,即行数。由于首部长度只有4位,所以IP首部的最大长度为(24-1)*4=60个字节
● 8位服务类型(TOS):包括一个3 bit的优先权子字段(现在已经被忽略),4 bit的TOS子字段和1 bit未用位但必须置0。4 bit的TOS分别代表:最小时延、最大吞吐量、最高可靠性和最小费用,4 bit中只能置其中1 bit,如果4 bit都为0,就意味着是一般服务
● 16位总长度:总长度指的是整个IP数据报的字节数,用总长度-首部长度,我们就可以知道数据部分的长度,这个字段占用16 bit,所以IP数据报的最大长度为216-1=65535字节。虽然最大长度可以达到65535,但是由于链路层的MTU限制,一般不会达到那么大
● 16位标识:标识字段唯一地标识主机发送的每一份数据报。在讨论分片和重组时,再详细讨论16位标识、3位标志和13位片偏移
● 8位生存时间(TTL):TTL设置了数据报可以经过的最多路由器数,它指定了数据报的生存时间。其初始值由源主机设置,每经过一个处理它的路由器,它的值就减1,当该字段为0时,数据报就被丢弃,并发送ICMP报文通知源主机
● 8位协议:协议字段也称作协议域,用来标记数据来自上层的哪一个协议:1表示ICMP协议,2表示为IGMP协议,6表示为TCP协议,17表示为UDP协议
● 16位首部检验和:检验和字段是根据IP首部计算的检验和码,计算方法为:首先把该字段设置为0,然后对首部中(不包括数据部分)每个16 bit进行反码求和,最后将结果存在该字段中。当接收方收到IP数据报时,同样对首部的每个16 bit进行反码求和,这一次因为包含了之前计算好的检验和,所以如果没有发生任何差错,那么接收方计算的结果应该为全1。如果不为全1,IP将会丢弃收到的数据报,但不生成错误报文,由上层去发现并处理
● 源IP地址和目的IP地址就比较直观了
● 选项:这个字段是数据报中一个可变长的可选信息,由于这些选项很少被使用,并非所有主机都支持,所以这里不做更详细的介绍,可参考相关RFC文档
由上面易知,当选项不存在时,IP首部的长度是固定的20字节
三、逻辑寻址
接下来我们就来讨论一下IP的主要功能,首先是逻辑寻址,在 TCP/IP-入门 中我们已经介绍了一些相关的概念,下面我们来回顾一下
● IP地址:IP为网络中的设备提供的身份标识,长32 bit
● 子网掩码:类似于IP地址,用于识别网络号(包括子网号)和主机号
了解了IP地址和子网掩码,我们就可以讨论子网划分了
子网划分
由于网络系统是由无数台网络设备通过传输介质互联在一起的,所以网络中的所有设备都在同一个集合中。当把数据从一台主机发送给另一台主机时,如果两台主机不是直接相连的话,需要经过中间设备,当网络中的设备数量太大时,传输效率会大大降低。如果把整个网络系统分成很多个子网,那么通过区别不同子网就可以增加传输的效率。子网划分的思想就是:将网络系统分成许多的大型网络,每个大型网络又包含许多子网,而每个子网内又包含许多主机
IP通过将IP地址分成不同的部分来标识网络号、子网号以及主机号。上一篇文章我们已经讨论了五类IP地址(并没有给出子网号部分),这里的大型网络的划分,就是依据五类IP地址来决定网络号的长度。而对于子网部分,子网号的长度由具体的网络配置来决定,也就是说子网号的长度不是固定的。网络号和子网号都确定以后,剩下部分就是主机号了。每个子网维护一个子网掩码,子网掩码由两部分组成,为1的位是网络号和子网号的部分,为0的部分是主机号的部分。通过地址类型、网络号、子网掩码和子网号,我们就可以知道一个IP地址是不是属于本子网。
举个栗子,假设本机所在网络使用B类地址,网络号是224.224.0.0,子网号是0.0.192.0,子网掩码是255.255.255.0。现在我就可以判断一个IP地址是不是跟本机在同一个子网内。比如IP地址 192.192.192.192,因为使用的是B类地址,所以我知道它的网络号是192.192.0.0,跟本机所在的网络不是同一个网络,就不继续判断了。比如IP地址224.224.132.22,它的网络号是224.224.0.0,跟本机在同一个网络,然后用子网掩码跟它做与运算,得到224.224.132.0,发现它的子网号是0.0.132.0,与本机所在的子网0.0.192.0不相同,说明不是在同一个子网。如果IP地址是224.224.192.23,跟前面的方法一样,我已经知道它跟本主机在同一个网络,并且它的子网号是0.0.192.0,所以它跟本机在同一个子网,只要再对比一下主机号,就可以知道这个IP地址是不是本机IP地址了
通常,判断一个IP地址是不是在本地网络就是直接用它跟子网掩码做与运算,然后对比网络号和子网号就可以得到答案
CIDR:无类型域间选路
IP地址是用32个bit来表示的,所以IP地址的数量是有限的,最多232-1个IP地址,并且其中有很多是不可用的。当网络中的设备达到一定数量时,IP地址将不够用了!一种解决方案是:使用更多个bit来表示IP地址,比如128个bit,这就是IPv6,这里暂不讨论。另外一种方法是:根据网络号的长度不同来用同一个IP地址表示不同的主机,这就是无类别域间路由。
前面我们讲到一个IP地址唯一地标识网络中的一台设备,CIDR的思想就是用一个IP地址标识多台主机。其思路就是使用一个斜线(/)作为分隔符,在IP地址后面跟一个十进制数值来表示地址中网络号所占的位数。例如:在CIDR地址205.123.196.183/25中,前25个bit是网络号(包括子网号),后面7个bit是主机号,这实现了IP地址的重用
特殊的IP地址
前面讲到,有一些IP地址是不可用的,具体有哪些呢?见下表
说明:0表示所有bit全为0;-1表示所有bit全为1;netid、subnetid和hostid分别表示不为全0或全1的对应字段。子网号栏为空表示该地址没有进行子网划分
这个表分为三个部分:头两项是特殊的源地址,中间项是特殊的环回地址,最后四项是广播地址
四、路由选择
我们先来了解几个概念
路由器(router)
前面一直在说路由器,到底什么是路由器?路由器是负责根据逻辑地址对通信流量进行过滤的设备,“又称网关设备(Gateway)是用于连接多个逻辑上分开的网络” --百度百科。简单来说,路由器就是为IP数据包进行导向的工具,告诉数据报下一站应该去哪
路由表(routing table)
路由表就是一张存储指向特定网络地址路径的表,其中保存着网络周边的拓扑信息.
路由器工作时,如果每次转发时都将数据报发送到任意的路由器或者某特定的路由器,那么传输的效率将会非常低下,因为每次发送都要重新路由(就像你去一个地方,从来不记住路线,每次去那个地方都要问路)。如果能在每次传输完之后记录一下本次传输的目的地址信息,那么下一次再需要发送给这个地址时,我就可以根据记录的信息找一条最短的路发送给它,而不用通过其他路由来转发(就是记住去这个地方的路线,下次自己就可以直接走过去),路由表就是用来保存这些传输路径的相关信息的
路由表中的每一项都包含下面这些信息:
● 目的IP地址:它既可以是一个完整的主机地址,也可以是一个网络地址,由标志字段来指定下一站路由器的IP地址,或者有直接相连的网络IP地址
● 下一站路由器:是指一个在直接相连网络上的路由器,通过它可以转发数据报。它不是最终目的地,但是它可以将数据报转发到最终目的地
● 标志:其中一个标志指明目的IP地址是网络地址还是主机地址,另一个标志指明下一站路由器是否真正的下一站路由器,还是一个直接相连的接口,为数据报的传输指定一个网络接口
路由选择
对于主机来说,路由选择是一件简单的事,如果目的主机与源主机直接相连,那么直接发送就可以了;如果没有直接相连,那么只要发送给默认路由,让路由器来转发就行了。
对于路由器来说,则要完成更多的功能,具体如下:
①搜索路由表,寻找能与目的IP地址完全匹配的表目(网络号和主机号都要匹配)。如果找到,则把报文发送给该表目指定的下一站路由器或直接相连的网络接口
②搜索路由表,寻找能与目的网络号匹配的表目。如果找到,则把报文发送给该表目指定的下一站路由器或直接相连的网络接口。目的网络上的所有主机都可以通过这个表目来处置
③如果上面两步都没有找到,那么寻找标为“默认(default)”的表目。如果找到,则把报文发送给该表目指定的下一站路由器
如果以上三步都没有成功,那么该数据报就不能发送。
如此循环,直到到达目的地或者TTL减为0.
五、查看接口和网络的有关信息
查看本机网络接口信息(包含物理地址、IP地址、子网掩码、MTU等信息): $ ifconfig
查看路由表信息: $ route
或者 $ netstat -rn
注:本文仅仅对IP做了一个大概的介绍,更多更细节的问题没有涉及,如当数据报发送失败时怎么处理等等。更详细的内容请参考RFC文档或者其他资料