
🔥海棠蚀omo:个人主页
❄️个人专栏:《初识数据结构》,《C++:从入门到实践》,《Linux:从零基础到实践》,《Linux网络:从不懂到不会》
✨追光的人,终会光芒万丈
博主简介:

目录
[3.1 4位版本](#3.1 4位版本)
[3.2 4位首部长度和16位总长度](#3.2 4位首部长度和16位总长度)
[3.3 8位服务类型](#3.3 8位服务类型)
[3.4 16位首部校验和](#3.4 16位首部校验和)
[3.5 8位生存时间(TTL)](#3.5 8位生存时间(TTL))
[3.6 8位协议](#3.6 8位协议)
[6.2.1 16位标识](#6.2.1 16位标识)
[6.2.2 3位标志](#6.2.2 3位标志)
[6.2.3 13位分片偏移](#6.2.3 13位分片偏移)
前言:
在前面的内容中,我们已经围绕 TCP 协议聊了很多:三次握手、可靠传输、确认应答、拥塞控制......
但如果继续往下追问一个问题:这些机制究竟运行在什么基础之上呢?
TCP 并不是直接在网络中" 发数据 "的。在它之下,还存在着一个更基础、也更关键的协议------IP协议。
这一篇,我们就暂时把目光从 TCP 的复杂机制中抽离出来,回到更底层的视角,看看 IP 协议到底在干嘛,以及网络通信最本质的问题究竟是什么。
一.IP协议的定位
在前面的章节中我们从初识到深入的讲解了TCP协议的相关内容,了解了TCP协议的各种可靠性的策略与机制,但是我们有没有想过这样一个问题:我们当时讲的内容是在逻辑上认为是端对端的,但是实际上TCP协议并不能自己直接通过它所制定的如超时重传,确认应答等机制来进行通信,那么它该怎么让自己的这些策略或者机制来实现呢?
答案就是通过IP协议层,TCP这一层它根本就不知道自己要发的东西是通过什么发的,它只是通过返回来的应答来调整策略,而IP协议则是真正通过网络来落实TCP协议所制定的规则和策略。
简而言之就是TCP协议是规则和策略的制定者,而IP协议则是执行者角色,IP协议提供了把数据从A主机跨网络送到B主机的能力!!!
二.IP的构成问题
在上面我们弄清楚了IP协议的定位后,回想一下我们在初识网络的时候讲过IP地址是一个4字节的地址,那么为什么通过IP地址就能够找到目标主机呢?
那么要想知道这个问题的答案我们就要来了解一下IP得知的构成,下面我们用一个例子来说明:

我们以我国的地图为例,比如说我现在在福建省,准备出去玩,那么周围的人问你要去哪里玩,你会说:" 我去故宫玩,我去兵马俑玩 "这种话吗?
肯定不会吧,你应该这样说:" 我去北京故宫玩,我去西安兵马俑玩 ",这样的回答才正常,而等我们真的到了北京和西安后,司机会问我们要去哪里,这时候我们才会说:" 去天安门,去兵马俑 "。
在上面的例子中,我们要去某个地方的时候,我们要去的地址 = 目标城市 + 目标景点,而映射到网络中其实就是IP = 目标网络 + 目标主机。
那么如何通过IP地址找到对端主机呢?下面我们来看:

这里我们先提前渗透一下,当主机B要给主机C传递消息时,主机B会先将消息发送给路由器F,路由器F再将消息发送给路由器G,以此类推,通过一条完整的路径最终将消息送到主机C的手中,这种方式叫做路由。
而主机B和路由器F是在一个子网中,路由器F和路由器G又在一个子网中,后面都是,所以我们这里就可以输出一个结论了:网络层(IP层)的本质就是在不同的" 子网 "间进行消息传递!!!
那么下面我们再补充一点:
主机:配有IP地址,要进行路由控制的设备
路由器:既配有IP地址,又能进行路由控制的设备
但是我们习惯性地把上面的两种设备都叫做" 节点 "。
三.IP报头
那么在介绍了上面两个部分后,下面我们来看看IP协议的报头构成是怎么样的吧:

从上图可以看到,IP协议的报头整体构成和TCP协议非常相似,报头同样都是至少20个字节,并且是可以携带选项的,其中不乏还有老熟人,那么下面我们就来介绍一下IP协议报头中的各种属性。
3.1 4位版本
这个其实很好理解,我们经常说或者听到IPV4,IPV6等字眼,其实这就是IP协议的版本,如果是IPV4的版本,那么该字段的值就为4,反之如果是IPV6的版本,该字段得知就为6。
3.2 4位首部长度和16位总长度
4位首部长度这个属性我们在TCP协议报头中也看到了,并且它们两个的含义也是相同的,都表示完整报头的长度,前面章节我们已经讲过了,所以这里就不过多介绍了。
那么对于任何一个协议,我们都要解决两个问题,那么其中一个问题就是:如何分离报头和有效载荷?
那么这里就要提到16位总长度这个属性了,它表示的就是整个报文的总长度,包括报头和数据,而报头的长度我们有4位首部长度,数据中也有Content-Length等自描述字段,所以分离报头和有效载荷的问题自然就迎刃而解了。
3.3 8位服务类型
依旧拿上面去旅游来举例,我们如果要去北京玩,去西安玩,即可以坐飞机,也可以坐火车,是根据自己的需求来决定的,那么在网络中也同样可以根据当前报文的需求来偏好某种通信方式,而8位服务类型就是来做这个工作的,下面我们来看:
8位服务类型(Type Of Service):3位优先权字段(已经弃⽤),4位TOS字段,和1位保留字段(必须置为0)。4位TOS分别表⽰:最小延时,最大吞吐量,最高可靠性,最小成本。这四者相互冲突,只能选择⼀个。
最小延时:这个我们可以简单理解为当报文需要以最快速度发送到对方手里时,就可以将该标识位置为1。
**最大吞吐量:**当需要每次发送的报文数据量很大的时候就可以将该标志位置为1。
**最高可靠性:**当传送的报文比较重要时,害怕丢包,那么就可以将该标志位置为1。
**最小成本:**要传输的数据在网络中的传输路线是有多条的,而将该标志位置为1就表示选择最" 便宜 "的那一条路线。
对于ssh/telnet这样的应用程序,最小延时比较重要;对于ftp这样的程序, 最大吞吐量比较重
要。
当报文在网络中转发时,网络设备就会根据报文中的8位服务类型来针对性的调整转发策略。
3.4 16位首部校验和
16位首部校验和的作用就是:检测IP报文在传输过程中,首部是否发生了差错。
虽然IP协议不像TCP协议一样会保证可靠性,但是最基本的查错功能还是要有的,16位首部校验和就是来做这个工作的。
3.5 8位生存时间(TTL)
对于这个相信我们大家并不陌生,为什么这么说呢?我们来看:

我们通过ping命令来访问百度的网站时,可以从打印的数据中看到后面跟的属性都有ttl这个属性,那个这个属性的生存时间到底表示什么意思呢?下面我们通过一个例子来说明:

我们要知道路由器这种网络设备肯定是有BUG的,即使是Linux也是有BUG的,那么当一台主机向目标主机发送消息时,如上图所示,一个路由器因为BUG,将应该发往正确路线的消息发到了错误路线的路由器手中,并且由于这个问题,报文最终甚至又发回到了发送方主机手中。
而上面这种现象叫做:报文路由的环路问题。
并且网络设备中还有一种设备叫做:集线器,这个设备的作用就是将信号放大,说白了就是一个信息可能会因为传输距离过长,在传输过程中信号越来越弱最终消散,而通过集线器就可以让它重新" 活过来 "。
那么这两种操作叠加在一起,那么这条消息不就在网络中能够永久存在了吗?
只有这一条消息你觉得可能没什么,那要是非常多的这种" 永生 "的消息呢?不就会很容易导致网络拥塞了吗?
所以为了解决这种问题,每个报文的报头中就有了8位生存时间这个字段,每经过一个路由器,该字段的值-1,一旦减为0,那么该报文就会自动消散。
那么讲到这里我们还剩下中间的三个字段没有讲,这3个字段与IP的分片与组装有关,等讲到这部分时我们在详细讲解。
3.6 8位协议
上面在16位总长度那里我们解决了第一个问题,那么在这里我们就要解决第二个问题:如何进行分用呢?
对于网络层来说,它的上面还有传输层,而传输层有很多协议,就如我们之前讲的:TCP/UDP协议,那么上面的问题就变为了:将报文交给上层的哪个协议?
那么这个问题的答案就在8位协议中,这里面保存的就是上层协议的协议号,就比如:TCP的协议号是6,UDP的协议号是17,所以未来对端的网络层就可以根据该字段讲报文交给上层相应的协议。
四.IP相关话题:子网划分,内网,公网,路由等
那么到这里我们就要更深入地去了解IP协议的一些相关知识,下面我们一起来看看吧。
4.1网段划分(子网划分)
那么我们首先要讲的就是网段划分的相关知识,或者叫子网划分,对于这个话题我们要解决3个问题:
1.谁来进行网段划分?
2.为什么要进行网段划分?
3.怎么进行网络划分?
其实我们现在就可以回答第一个问题:就是运营商,在我国就是由移动,联通,电信等运营商搭建了整个网络的基础设施,所以我们才能够进行网络通信。
那么下面我们要解决的问题是为什么要进行网段划分,那么下面我们用一个例子来找到答案:

现在一所学校分为上图的6个学院,学校根据学院的不同设计了不同的学号,就如计算机学院的学生学号前面两位都是01,机械学院的学生前面两位都是06。
我们要知道IP地址是被精心设计过的,IP = 网络号 + 主机号,通过IP地址我们能找到任何一台主机,而同样的,我们的学号也是被学校精心设计过的,每个学生的学号都具有:
1.唯一性
2.具有很强的指向性
通过学号就能精准地找到每一个学生,那么下面我们接着看:

那么每个学院都有院学生会,并且每个学生会都要有一个学生会主席,但是学校也不可能让这些学生会各自为政,所以还会有一个校群,未来学校里面有什么事情都会先在这个校群通知。
通过这种方式,整个学校建立起了一个简单的" 网络拓扑 "结构,那么这有什么用呢?我们接着看:

那么某一天计算机学院的一名学生:张三,在操场上捡到了一个钱包,里面有一张学生证,但因为磨损的原因,只能够看到学号是:06321,也就是机械学院的李四,但是张三不知道啊,他连自己学院的学号有时还记不清楚,更别说其他学院的学号了。
那么张三有一种做法,那就是:拿着这张学生证在学校里面一直找人问,以此来找到目标学生,他的这种行为本质就是在线性遍历,显然效率太低了。
所以他在他们学院的院群中@了一下院学生会主席,说:" 我捡到了一个钱包,学号为:06321,我的联系方式为:XXXXXXX ",学生会主席看到这个学号后,立马就知道:" 哦,这是机械学院的学生的钱包 "。
于是他就在校群中@了一下机械学院的学生会主席,将张三发的消息转发给了机械学院的学生会主席,然后机械学院的学生会主席一看确实是他们学院的学生,所以就在机械学院的院群@了所有人,询问了这是谁的钱包,于是就找到了李四,随后张三和李四就在线下将钱包归还了。
并且这个过程是很快的,几分钟就能完成。

在上面的的这个例子中:每个学院就相当于子网,而校群就相当于公网,每个学院的学生会主席就相当于路由器,张三和李四就是两台主机,张三发在群里的信息就相当于报文。
那么这里面还有很多问题,下面我们来一解答:
1.计算机学院的学生会主席看到信息后,他最关心的是:06321这个学号还是06这个开头?
那必然是06这个开头,学校那么多学生,他也不可能记住每一个学生的学号啊,但是通过06这个开头他就能判定这是机械学院的学生。
所以我们要输出的结论就是:当报文到达目标网络之前,最关心的是网络号!!!
2.为什么张三的第一种做法效率太低?为什么第二种方法效率高呢?
因为查找的本质就是一个淘汰的过程,而第一种做法一次只能淘汰一个人,所以效率很低。
而第二种做法通过06这个开头一次就能淘汰除机械学院外的所有学生,映射到网络中就是以群的方式,淘汰了大量主机,这样做效率就会很高。
那么淘汰效率高是基于什么呢?
是因为学号是被学校精心设计过的啊,它是具有唯一性,具有很强的指向性的,IP地址也是如此。
说白了就是因为进行了网段划分,才使得淘汰效率高。

上面的例子终究不是真正的网络图,而上图则是真实的网络结构。每台主机都有自己的IP地址,IP地址被分为网络标识和主机标识,就相当于上面的院号+序号,下面我们来看网络号和主机号的具体含义:
⽹络号: 保证相互连接的两个网段具有不同的标识
主机号: 同⼀网段内, 主机之间具有相同的⽹络号, 但是必须有不同的主机号
而这中间还少不了路由器这个关键设备,路由器不仅要知道发送方的IP地址,还要知道接收方的IP地址,所以在其内部会有两张网卡。
那么下面我们就要来解决第三个问题了,网段划分是怎么划分的。

过去曾提出一种划分网络号和主机号的方案,把所有的IP地址划分为五类,就如上图所示。第1位为0的就属于A类IP,第2位为0的就属于B类IP,以此类推。
A类:0.0.0.0到127.255.255.255
B类:128.0.0.0到191.255.255.255
C类:192.0.0.0到223.255.255.255
D类:224.0.0.0到239.255.255.255
E类:240.0.0.0到247.255.255.255
那么按照上图的划分规则这五类IP地址的范围我们就可以计算出来,并且A类的主机号最长,所以它能表示的主机数是最多的。
但是随着网络的飞速发展,这种划分方案的局限性很快就显现出来了,大多数组织都申请B类网络地址,导致B类地址很快就分配完了,而A类却浪费了大量的地址。
例如, 申请了⼀个B类地址, 理论上⼀个子网内能允许6万5千多个主机。A类地址的子网内的主机数更多。
然而实际网络架设中, 不会存在⼀个子网内有这么多的情况. 因此大量的IP地址都被浪费掉了。
所以针对这种情况提出了新的方案,称为CIDR(Classless Interdomain Routing,无类别域间路由):
1.引入一个额外的子网掩码(subnet mask)来区分网络号和主机号
2.子网掩码也是一个32位的正整数,通常用一串" 0 "来结尾
3.将IP地址和子网掩码进行" 按位与 "操作,得到的结果就是网络号,或者说子网地址
4.通过这种方式将网络号和主机号进行划分,那么就与这个IP地址是A类,B类还是C类无关了
那么下面我我们来通过一个例子来更好地理解子网掩码的作用:

比如上面例子中的子网掩码前24位都为1,那么得到的结果中前面24位都为网络号,只有最后8位才是主机号,那么这个子网中就只能有2的8次方也就是256个主机,下面我们再来看个例子:

这个例子中子网掩码的前28位都为1,也就是网络号是28位,只有最后4位才表示主机号,那么经过计算后,这个子网中就只能有2的4次方也就是16台主机。
通过子网掩码,我们根据一个子网中的实际主机数量,就可以通过灵活地改变网络号和主机号的范围,让IP地址利用的更加充分,也就是子网掩码的本质就是:为了提高分类划分的IP地址的利用率!!!
4.2特殊的IP地址
当我们通过子网掩码进行按位与操作后,得到了一个子网地址,那么根据后面的主机号就可以表示该子网的范围了。
而在这个范围中IP地址主机号全部为0的叫做这个子网的起始地址,是不能表示一个主机的;而同样的,IP地址主机号全部为1的叫做广播地址,是用于给同一个链路中相互连接的所有主机发送数据包,同样也不能用来表示一台主机。
所以在一个子网中,我们算出来的范围其实要-2才是该子网中真实的主机数量。
4.3IP地址的数量限制
我们知道,IP地址(IPV4)是一个4字节32位的正整数,那么一共也就是2的32次方也就是大概43亿左右的IP地址,而TCP/IP协议规定,每台主机都要有一个IP地址。
那么真的意味着能有43亿台主机接入网络吗?
答案肯定是不会的,由于一些特殊的IP地址的存在,数量远不足43亿,并且IP地址并非是按照主机台数来配置的,而是每一个网卡都需要配置一个或多个IP地址。
虽然CIDR在一定程度上缓解了IP地址不够用的问题,也就是提高了利用率,减少了浪费,但是IP地址的绝对上限并没有增加,所以依然不是很够用,那么就要有相应的解决方式:
1.动态分配IP地址:只给接⼊⽹络的设备分配IP地址。因此同⼀个MAC地址的设备,每次接⼊互联⽹中,得到的IP地址不⼀定是相同的。
2.NAT技术
3.IPV6:IPV6并不是IPV4的简单升级版,他们两个是互不相干的,彼此不兼容,IPV6用16个字节128位来表示一个IP地址。
4.4私有IP地址和公网IP地址
如果一个组织内部组建局域网,IP地址只能用于局域网内的通信,而不能直接连到Internet中,理论上,可以使用任意IP地址,但是RFC 1918规定了用于组建局域网的私有IP地址:
1.10.*,前8位是网络号,共16777216个地址
2.172.16.*到172.31.*,前12位是网络号,共1048576个地址
3.192.168.*,前16位是网络号,共65536个地址
包含在这个范围中的,都是私有IP,或者叫内网IP,其余的则称为公网IP。
并且私有IP只能用来构建子网,不能出现在公网上,至于原因,后面我们就知道了。而我们平时能接触到的网络,一般都只有私有IP,没有公网IP。
既然我们平常接触不到公网IP,也就是我们使用的都是私有IP,那也就意味着我们得组建局域网,那由谁来组建局域网呢?
答案就是我们的家用路由器,没错,路由器不仅仅具有路由功能,还有组建局域网的功能,下面我们来看:

我们来看这张图,在我们的家用路由器中会内置DHCP服务,也同时会内置一个子网地址,就比如:192.168.1.0,而家用路由器自己占一个IP地址。
未来我们通过输入账号密码成功连接到我们的家用路由器后,家用路由器就会通过DHCP服务为我们的设备分配一个没有使用的私有IP,其实就是分配一个没用过的主机号,之后我们就能上网了。

但是不是只有张三家安装了家用路由器,李四家也买了家用路由器,并且内置的子网地址和张三家是一样的,并且非常巧合地,张三家的电脑私有IP地址和李四家的电脑私有IP地址是相同的。
那么这代表着什么呢?
这不就相当于变相地增加了IP地址的绝对上限了,可能有人会对上面的现象有所疑惑:为什么家用路由器内置的子网地址是相同的?
这个问题的答案和上面私有IP不能出现在公网上是同一个答案,我们下面会讲。
所以张三家的路由器就构建了张三家的子网,李四家的路由器构建了李四家的子网,但是我们要知道我国的网络基础设施都是由运营商来完成的,而我们的家用路由器是无法直接接入网络的,还要连接着运营商的路由器才行,所以:

我们再看这张图,家用路由器左边连接着我们家庭的子网,右边连接着运营商服务器,而运营商路由器也是路由器啊,所以它也会构建自己的子网。

而运营商构建的子网地址我们以:10.1.1.0为例,那么我们的家用路由器在该子网中就会有自己的私有IP地址,这个IP地址叫做:WAN口IP。但运营商路由器的WAN口IP对应的则是广域网,即公网。
也就是我们的家用路由器横跨两个子网,左边是我们的家庭子网,右边是运营商路由器构建的子网,所以在其内部就会有两个IP地址,其实也就是会有两个网卡。
那么这里我们就可以输出一个结论了:家用路由器的本质就是运营商路由器搭建的子网中其中一个主机节点!!!
所以我们要上网就必须经过运营商路由器,所以为什么我们不科学上网的话就无法访问国外地址呢?
答案就是当运营商路由器看到我们要访问国外网站,就直接把你的请求给丢弃了,我们的请求发不到国外的服务器,自然也就无法看到网页内容了。
那么下面我们就要来探究:我们的客户端是如何将数据发给公网主机的呢?下面我们来看:

现在如果我们使用私有IP地址,我们现在要将数据发送给网上的一台主机上,那么我们的主机识别到我们发送的数据不是在当前子网中,所以它将数据交给了我们的家用路由器,那么我们的家用路由器也同样识别到这不是发给当前子网内的,所以最终它将数据交给了运营商路由器。
因为运营商路由器的WAN口IP对应的是公网IP,于是它在公网中找到了对应主机,并将数据交给了目标主机,而当目标主机处理完请求后,要将消息返回时,问题就出现了:因为私有IP是可以重复的,那么它此时该将应答报文交给谁呢?交给哪台主机呢?
答案并不知道,所以这就是私有IP地址只能用来构建子网,而不能出现在公网上的缘由,就会导致上面的问题,那么该如何解决呢?

那么解决方式就是:数据在由内网发送到公网的过程中,路由器会自动进行内网IP替换,用路由器自己的WAN口IP将其替换掉,这种技术叫做NAT技术。
那么最后交给公网中目标主机的报文中发送地址就变为了运营商路由器的公网IP地址,那么当对端主机处理完请求后,就会将运营商路由器的公网IP作为目的地,从而成功将应答报文交给了运营商路由器。
那么后面的过程就是再将目标地址一步一步替换为家庭中的主机地址,这个过程叫做内网转发,具体的转发过程我们在后面的章节中在讲解。
那么上面的为什么家用路由器内置的子网地址是相同的问题这里就可以解答了,那就是:家庭的私有IP地址只在家用路由器所构建的子网中有效,出了这个子网就无效了,因为会被替换,所以并不会影响到其他家庭的子网,相同又如何呢?
4.5尝试理解公网
上面我们的视角一直停留在子网中,那么下面我们就将视角切换到公网中,但是真实的公网网络结构非常复杂即涉及到划分公网IP的组织:ICANN,还要在全球范围内进⾏区域划分,⽐如亚太,北美,欧洲等,⼜要考虑各个国家内部的ISP代理,整体拓扑⾮常复杂,所以我们简化所有过程,简单理解公⽹即可。

那么下面我们先来看第一部分,我们现在就将整个世界的国家挑出来几个来举例,我们将IP地址的前8位作为网络号进行国家划分,就如:俄罗斯的IP地址前八位就以1开头,美国就以2开头,以此类推。
而每个国家都有相应的国际路由器, 而将这些国家的国际路由器联合在一起就形成了国际骨干网络(公网),并且这些路由器中还配置了路由表,那么它有什么用呢?
就比如:当俄罗斯的国际路由器向中国的国际路由器发送报文时,通过路由条目交换算法就可以交换两者的网络信息,就如上图所示的那种样子,并将其保存在路由表中,那么通信的国家多了,每个国家的路由器中不就都有其他国家的网络信息了吗?
而上面的过程不就相当于第一层子网划分吗?
那么只有国家间能够通信也是不够的,下面我们来看:

那么在我们国家,在国家划分8位的前提下,我们在划分8位作为国内省份,比如:陕西省就以5.1开头,河南省就以5.2开头,而每个省都有自己的省间路由器,这些省间路由器联合在一起就形成了我们国内骨干网络(公网)。
而这些省间路由器中也同样配备了路由表,和上面国际路由器一样,省间路由器在互相通信的同时,就会通过路由条目交换算法来交换各自的信息,那么每个省份就会有其他省份的网络信息。
那么这不就相当于第二次网络划分吗?
那么还有,不只有省间通信:

在省之下还有市级别,在前面划分了国家,省份的网络号后,市级划分再占4位,相当于前20位为网路号,就如:西安市的前缀就是5.1.16,延安市的前缀就是5.1.32,并且通过这些市级别的路由器也同样构成了我们国内的骨干网络(公网)。
其实到这一层市间路由器相当于运营商路由器了,它下面就是我们各个家庭的子网了,而这不就相当于第三次网络划分吗?
为了让大家更好的理解这整个过程,下面我们用一个例子来说明:

比如现在俄罗斯的国际路由器要访问IP地址为:5.1.16.3,那么这个信息是如何到达目的地的呢?
整个过程就是:俄罗斯的国际路由器看到前缀是以5开头的,知道这不是发给自己国家的,于是就拿着这个IP地址与子网掩码255.0.0.0进行计算,得到了5.0.0.0的网络地址,然后在其内部的路由表中通过比对就就发现这是要发给中国的信息。
于是就将信息发给了中国的国际路由器,而中国的国际路由器在收到信息后,看到确实是发给我国的信息,于是它就拿着子网掩码255.255.0.0进行计算,得到了5.1.0.0的网络地址,然后在路由表中通过比对发现这是发给陕西省的信息,于是就将信息发给了陕西省路由器。
陕西省路由器在收到消息后,判断出这是发给自己省份的信息,于是它就拿着子网掩码266.255.240.0进行计算,得到了5.1.16.0的网络地址,通过比对发现这是发给西安市的信息,于是就将信息发给了西安市路由器。
西安市路由器在收到消息后,判断这确实是发给自己的信息,那么最终这条消息从俄罗斯发到了西安市路由器的手中,或者说发到了运营商路由器的手中。
而上面我们也说了,公网所发的消息中目的地最多只能是运营商路由器的公网IP地址,后面要想发到具体某个家庭的主机中,就要通过内网转发的方式来进行了,这我们放到后面再讲。
那么通过上面这个过程的讲解,我们对于公网就有了一个基本的认识,虽然它实际上比我们画的要复杂的多。
五.路由
路由的概念就是在复杂的网络结构中,找出一条通往重点的路线。

经过上面知识的讲解后,我们再看这张图就能有一个更深刻的理解了,就能理解从一个子网跳到另一个子网是什么意思了。
IP数据包的传输过程也和问路是一样的:
1.当IP数据包, 到达路由器时, 路由器会先查看⽬的IP
2.路由器决定这个数据包是能直接发送给⽬标主机, 还是需要发送给下⼀个路由器
3.依次反复, ⼀直到达⽬标IP地址
那么如何判定这个数据包该发送到哪里呢?
答案就是通过每个节点维护的的路由表,那么它长什么样子呢?下面就我们来简单看一看:

上图就是一张非常典型的路由表,在这个路由表中有很多种属性,下面我列举几种来介绍一下:
Destination:表示的就是目标网络地址
Genmask:表示的就是子网掩码
Getway:表示的是下一跳的地址
Flags:U标志表⽰此条⽬有效(可以禁⽤某些条⽬),G标志表⽰此条⽬的下⼀跳地址是某个
路由器的地址,没有G标志的条⽬表⽰⽬的⽹络地址是与本机接⼝直接相连的⽹络,不必经路由器转发。
从上图可以看到Flags为U的,它们的Gatrway都为*,表示没有下一跳的地址,如果要发送信息给这些网络地址,可以直接将信息发到对端主机上,就不需要经过路由器转发。
那么下面我们用一个简单的例子来说明:
要发送的数据包的目的地址是192.168.56.3,那么过程就是:
1.跟第⼀⾏的⼦⽹掩码做按位与运算得到192.168.56.0,与第⼀⾏的⽬的⽹络地址不符
2.再跟第⼆⾏的⼦⽹掩码做与运算得到192.168.56.0,正是第⼆⾏的⽬的⽹络地址,因此从eth1接⼝发送出去
3.由于192.168.56.0/24正是与eth1接⼝直接相连的⽹络,因此可以直接发到⽬的主机,不需要经路由器转发
那么相反的如果要发的数据不在该路由表中,那么就会使用default(默认路由或缺省路由),上图就是将数据发送给家用路由器了,就说明要发送的目标地址就要经过路由器转发了。
六.IP分片与组装

早在上面讲解IP报文的报头属性时,我们当时并没有讲第二行的这三个属性,但还是我们说这三个属性与IP的分片与组装有关,那么下面我们就来讲讲IP的分片与组装话题。
6.1为什么要分片?
那么首先我们就要来了解一下IP报文为什么要分片?

因为当网络层讲IP报文交给数据链路层的时候,数据链路层规定:上层也就是网络层交给链路层的数据最大不能超过MTU,也就是1500字节,超过1500字节IP报文就必须分片了。
至于为什么是1500字节,这就是属于数据链路层要讲的知识了,我们后面再讲。
那么我们先来思考一个问题:分片与组装的过程,传输层需要知道吗?
答案是不需要,这里就要输出第一个结论:分片与组装的过程,传输层不需要知道,对于传输层而言,它只需要知道发送的报文是否到达对端主机手里,这中间发生的过程它不知道,它也不需要知道。
6.2什么是分片?
那么下面我们就来介绍一下:什么是分片?

分片简单来讲就是将原IP报文的有效载荷分为多个部分,并且这里我们就要输出第二个结论:分片不是简单的对IP报文进行分片,而是要对每一片都添加IP报头。
所以分片后每一片的大小都是有效载荷+IP报头,那么简单介绍了分片的含义后,下面我们就要来介绍与分片有关的IP报文中的三个字段了:
6.2.1 16位标识
这个字段的作用就是标识一个报文的唯一性,什么意思呢?
就是如果分片了,那么每一个分片报文中的该字段都是相同的,这样就可以知道该分片报文属于哪一个IP报文了,有助于后面组装的过程。
6.2.2 3位标志
这三个标志位第一位保留(保留的意思是现在不用,但是还没想好说不定以后要用)。第二位如果置为1,表示禁止分片,那么这时候如果报文长度超过了MTU,那么数据链路层就会将该IP报文给抛弃掉。第三位表示" 更多分片 ",如果分片了的话,最后一个分片的该标志位为0,其余分片报文的该标志位为1,类似一个结束标志。
6.2.3 13位分片偏移
这个字段表示分片相对于原始IP报文开始处的偏移量,其实就是在表示当前分片在原报文中处在哪个位置,这个开始处就是有效载荷的开始处,不是整个IP报文的开始处。
6.3如何组装?
上面介绍了分片的相关知识,那么下面我们就要来讨论一下分片后如何组装的问题。
那么对于这块的知识,我们要解决两个问题:
1.传送过去的IP报文,有的分片了,有的没分片,如何在其中挑选出来分片的报文?
2.怎么保证挑选出来的报文,挑完整了?如何组装?
那么下面我们先来解决第一个问题:
这个问题的答案就在于3位标志这个字段,如果是分片报文,那么第三位就应该为1,根据这个我们就能够从中挑选出大部分的分片报文,为什么说是大部分呢?
因为最后一片的第三位是0,只看第三位是挑不出来最后一片的,那么就没有办法判断了吗?
当然是有的,第三位是0,但是它的IP报头中的13位分片偏移一定是大于0的,所以根据这个就可以将最后一片也挑选出来。
那么下面就来解决第二个问题:
IP报文进行分片无非就是分为了3个部分:第一片,中间片,最后一片。
所以要想挑出完整的分片报文,就要针对不同的分片来进行挑选,从上一个问题中我们已经将分片报文挑选出来了。
但是这些分片报文可能属于不同的IP报文,所以我们首先要做的就是根据16位标志,从中挑选出每一个IP报文的分片报文。
那么如何将一个IP报文的分片报文进行组装呢?
最后一片就不说了,而第一片与中间片的不同是它的13位分片偏字段的值为0,通过这种方式我们就能挑选出第一片和最后一片了,那么中间片的排序就可以根据它们IP报头中的13位分片偏移从小到大进行排序。
那么最终我们就可以按照顺序排列出一个IP报文的所有分片报文,不就可以进行组装了吗?
6.4细节问题
对于上面的过程我们再补充一些细节问题。
细节1:
如果一个IP报文的分片报文在传输过程中丢了,那么会发生什么呢?
答案就是任意分片丢失,对端的网络层就会将所有的分片报文给丢弃掉,通过超时重传机制将整个报文进行重传。
并且传输分片报文也会变相的增加丢包概率,什么意思呢?
如果传输一个报文的丢包率为1%,那么也就是传输成功的概率就是99%,而一个传输一个IP报文的所有分片报文,就比如说传输4个分片报文,那么全部完整传输过去的概率就是:99%*99%*99%*99%,得到的结果一定是比99%要低的,并且通过1-99%*99%*99%*99%就可以算出整体的丢包率,也肯定是比1%要高的。
所以在实际的IP通信中,分片这种方式并不能作为主流,那么这里也可以回答在讲解TCP协议的滑动窗口时其实是有一个问题的:为什么不将滑动窗口中的数据一次性全部传输给接收方,而是要分成多次?
答案就是为了避免进行IP分片,一旦IP分片,丢包率就增加了。
细节2:
通过IP报头中的16位总长度我们可以计算出一个IP报文最大可以是2的16次方也就是65536个字节,那么问题就来了:如何用13位分片偏移来表示16位的大小呢?
也就是如果分片了,最后一片的偏移量可能是65520,但是2的13次方也就8000多,那么该如何表示呢?
那么这个问题的答案我们就要补充13位分片偏移的概念了,也就是:分片偏移字段用于表示当前数据片段相对于原始数据包(未分片时的原始 IP 数据包)的偏移量,但是这个偏移量是以 8 字节为单位来计算的,也就是每个分片的大小(报头+数据)必须是 8 字节的倍数。
也就是存储在13位分片偏移中的数值其实是:实际的偏移量 / 8,就比如上面的最后一片的实际偏移量是65520,但是存储在13位分片偏移中的数值却是8190,所以为什么要以8字节为单位呢?
就是为了能够用13位分片偏移来表示16位总长度。
以上就是IP 协议到底在干嘛?------从通信本质理解网络世界的运行逻辑的全部内容。