网络基础(4)IP协议
经过之前的学习对传输协议的学习,对于传输协议从系统底层到应用层对于socket套接字的学习已经有了一套完整的理论。
对于网络的层状结构,现在已经学习到了应用层和传输层:
在之前的学习中,通信的双方都只考虑了双方的传输层的东西,对于其它层的东西都没有进行考虑。也没有考虑过中间网络形态的问题,也没有考虑过数据包是如何从A主机跨网络传到B主机的。对于这些信息就需要学习网络层。
下面是一个真实的简单网络拓扑结构:
有了TCP协议对于报文的发送和接收就已经保证了可靠性,但是真实的网络环境并不是把主机A的信息直接就跨网络传到了主机C。这个信息在网络中要经历下面的步骤:
注意上图中的直接发送的那一条线是错误的。
但是思考一下对于路由器H来说既可以选择将信息交给路由器C也可以交给路由器J为什么会交给路由器C呢?对于其它的路由器也有这样的问题。为什么会选择出一条路径呢?
也就是说在路由器发送信息的时候是存在路径选择的。
在网络中支持路由器进行路径选择的协议就是IP协议,虽然网络层的协议不止存在IP协议,但是在网络层中最重要的协议就是IP协议。
只有这个数据包发送到了C主机中才能对这个数据包进行自底向上的交付,才能到达对方的传输层最后到达应用层。否则之前在传输协议学的流量控制,拥塞控制,超时重传,快重传都是没有意义的。
所以总结来说IP协议提供了一个能力能够完成将数据包跨网络从一个主机发送到另外一个主机。那么这个有能力是否就能够100%保证数据包一定能够送达呢?当然是不一定的。也是存在概率无法送到数据包的。
所以这里对于能力下一个概率就是具有较大的概率
如何保证这个信息一定要发送到呢?
之前学习的传输层的策略就起到作用了,只要某一次发送信息失败了,那就重发直到这个信息成功被对端主机收到。就和一个有能力考到100分的学生张三(可能考到100分),而张三没有考到100分的时候父亲就直接让全校重考。直到张三考到100分。张三的父亲就是TCP而张三就是IP协议。
通过两者的配合就能够保证数据包能够将数据包跨网络可靠的从B主机发送到C主机。
而这个数据包中的数据就是应用层要的数据
总结就是传输层TCP提供可靠性策略,网络层提供能力把数据从A主机送到C主机。
下一个问题:
现在我在辽宁,我想和我的朋友想去北京的故宫玩一下,那么能否坐飞机直接到达故宫的门口呢?
当然不能
我们需要先做飞机到城市,在使用其它的交通工具到达故宫门口。
所以当我想要出去玩的时候目标地址一般是由两个部分组成的。
对于网络传输数据包也是这样的。这里就可以先提出一个结论:
IP地址是可以被拆分成为两个部分的
由以上两个部分构成了一个IP地址。
下面画一个简单的示意图:
从上图看主机B和路由器F之间没有任何的联系但是其实主机B和路由器F一定是在一个局域网中的。而路由器F也一定和其它的路由器也处于在一个局域网中的。其它的路由器也是一样的:
而在主机B和路由器F所在的这个局域网中一定还存在其它的主机。
主机B所在的局域网中是存在其它的主机的,只不过主机B选择了将报文交给了路由器F并且路由器既然能够做转发功能那么路由器一定是横跨了两个子网的。
这样当路由器F在收到报文之后就可以将报文转发给路由器G,不断往前直到被主机C收到一个报文。
由此就需要知道一个点就是任何一个主机一定是处在它所在的一个子网中的。
所以将主机B中的报文交给路由器F的本质是将数据报文从一个子网传输到另外一个子网中。
只要到达了目标主机所在的子网中,此时的这个子网的信息也就是目标网络号。到达了网络号之后再去寻找主机。
这里回到下面的这个图:
主机B是我的电脑而主机C是我朋友的电脑,所以我和我的朋友准备自己的路由器这是没有问题的,那么上图中的其它路由器是有谁准备的呢?
这里需要知道:
这个人就是运营商,运营商建立基站,搭建网线等等基础网络设置。
所以当学习网络的时候突然出现的名词也是有人经过精心的设计之后提出的名词。
之后会说明在国内这个运营商扮演的是什么样的一个角色。
学习网络的时候运营商也是很重要的。
IP协议报文
这里来看一下IP协议的报头:
对于每一种协议都有两个问题:
1.如何进行报文和有效数据的分离
2.如何进行分用(如何交给上层的哪一个协议)
对于第一个问题这个协议其中的一个字段四位首部长度和TCP的四位首部长度一样大小是从0到15的表示的报头的大小也是从:
[0,60]的,对于IP协议的报头来说标准的报头长度大小为20字节。
而16位的总长度 = 报头长度(选项)+有效载荷。
这样就能得到某一个报头的长度,然后通过报头就能够读取到一个完整的报文。然后通过16位总长度就能够完成报头和有效载荷的分离(总长度减去报头长度就等于有效载荷)。
现在分离已经能够解决了,如何解决分用呢?
在解决分用之前还有一个小知识需要知道那就是当我的发送端是使用TCP协议封装的报文,那么对端主机在进行接收报文的时候一定也是使用TCP的方式进行报文的解包的。
如果发送方使用的是UDP那么接收方也一定会使用UDP进行解包。
而在IP字段中有一个8位协议的字段,这个字段是发送方进行填充而接收方进行识别的。而这个8位协议就是表示发送方使用什么协议封装的报文。例如对于上层来说TCP是1,UDP是2。如果使用的是TCP封装报文,那么这里的字段就是1,否则这里的字段就是2。这里的填写的是1还是2就决定了对方使用的是什么协议进行读取。
所以如何进行分用呢?在这个报文中存在一个8位协议的字段,这个字段就是告诉IP协议这个报文要交给上层的TCP协议还是UDP协议。由此就解决了向上分用的问题。这个字段是由发送方填写的。
第一行字段中还有一个四位的版本:
这个版本一般填写的都是IPV4对应的版本号也就是4。
到这里IP协议报头中第一行的字段就全部解决了,同时也说明了IP协议是如何解决数据包的向上交付,以及有效载荷和报头分离的问题。
上面学习的这个报头也是IPV4协议对应的报文。
还有一种IP协议也就是IPV6协议,这两种协议是互相不兼容的。那么为什么会出现IPV6协议呢?
因为在IPV4协议中留给IP地址的字节数为4字节32个比特位,能够表示的IP地址也就是42亿多。之前的人们认为这么多的主机已经足够了。但是随着各种智能设备的出现。伴随着的就是更多的设备进入到网络中。
就导致了IP地址不够了。也就出现了很多的解决方法其中IPV6(使用了16个字节来表示IP地址)就是一种(IPV6我国是搞的最好的国家),但是IPV6和IPV4不兼容,这是不被广泛使用的一个技术原因(因为全球存在很多的计算机如果想要升级时很麻烦的)。还有一个原因和政治有关。就不多说了。
虽然国外不支持但是国内的APP基本都是支持了的(我国现在对于大型的互联网公司基本都要求要支持IPV6)。还有一个字段是8位服务类型,这个类型了解一下即可
其中这四个特征只能选择一个。最小延时的特征如何做到的呢?只要让路由器在处理报文的时候优先处理(排在前面或者直接不排队),只要每一个路由器都使用这样的原则的话,最小延迟就有了。还有其它的选项都是这样出现的。总结就是这些选项是会影响到我的。
到这里IP报头的第一行就已经全部解决了。
第二行的字段之后说明。
现在回到网络的问题上,在现实生活中网络是很大的,那么在网络中是否会出现下面的情况呢?
出现了网络环路问题。如果出现了这种情况这个报文会被一直转发。不可能出现发不动的情况,因为路由器一直在充电。那么怎么办呢?每一次的转发都是会消耗资源的。这就很浪费资源。如果这样的报文多起来了,会导致路由器中的废弃节点越来越多,浪费的资源也会越来越多。为了解决这样的问题,所以必须给报文设置生命周期。
这个生命周期也就是TTL字段(8位生存时间):
如果某个报文的TTL变成0了路由器就不会转发这个报文而是直接将这个报文丢弃。这样即便是环路问题也可以在网络当中解决了。
TTL就是IP报文在路由器转发过程经历的路由器的跳数
要设置这个上限的原因就是为了解决环路问题。然后8位协议的作用也说明了是用于交给上层完成向上交付的问题的。
也就是检测当前的报文是否是完整报文的问题。
到这里IP报头的第三行就解决了。
然后还有两个字段一个是32位源IP地址,和32位目的IP地址。这也是为什么在之前的应用层使用套接字的时候,客户端的IP地址需要转化为四个字节的IP地址为什么是四个字节呢?就是因为在IP报文中需要的就是32位源IP地址。
在使用下面这样的客户端的时候:
IP地址就被填充到了IP报文的报头中,而端口号就被填充到了TCP/UDP协议的端口号中。由此我的一个报文就知道了要去哪一个主机上的哪一个进程了。
这些都是被设计好的。对于这两个字段暂时没有什么说明的,表明当前报文从哪一个主机来,需要到哪一个主机处。
此时就存在一个问题了:
TCP报头和IP报头在格式上很像。
标准报头长度都是20都有选项。
这也是为什么网络协议栈使用TCP/IP协议来命名,主要原因就是:一个解决可靠性一个解决能力问题,所以能够将网络报文中一个主机可靠的传输到另外一个主机上。这个不就是网络的核心能力吗?
所以网络协议栈使用了这个TCP/IP来进行命名。
之前在讲解传输层的时候说明过在传输层中存在一个sk_buff结构体,每一个报文到达传输层之后sk_buff。都会进入到传输层的这个发送队列中
然后在这个结构体中不同的指针指向的是缓冲区的不同的位置。不同位置的空间也有不同的名字:
当然除了这两个空间之外再往后面也还是存在空间的。
而在应用层写的数据就放在下面的位置:
然后在传输层增加了TCP的报头,如何增加的呢?因为TCP报头也是一个结构体对象,将TCP报头的对象定义出来之后,移动sk_buff中的指针将其移动一段位置,用于填充TCP报头对象。
下体就是将data指针往上移动sizeof(tcp_head)然后将对象往这个空间中一填写,就完成了对TCP报头的增加
现在这个结构体是在传输层,完成各种工作之后要向下进行交付。
这个sk_buff的结构体对象是没有变化的而是将这个对象移动到了IP对应的一个发送队列中。这样就完成将报文的向下交付。至于IP报头的增加和上面TCP报头的增加使用的是一样的方式
所以整个报文在向下进行交付的时候都是sk_buff在进行向下交付。之后将这个报文交给数据链路层也是一样的。
这样的话每一层都可以提供一个队列的机制,让其完成将报文的不断往下交付,在sk_buff的结构体中,也是存在一个指向队列前一个节点/后一个节点的指针的。
这个sk_buff不断的增加报头,然后移动到下层的队列中的过程就是封装。
网段划分(重要)
为了理解这个网段划分从三个问题上入手进行理解:
第一个:网段划分是什么
第二个:为什么要进行网段划分
第三个:网段划分要怎么办
网段护划分怎么做的
之前已经说明过了:
IP地址 = 网络号+主机号
从下图可以得到一些信息:
在不同的子网中的主机拥有不同的网络号,而在同一个子网中不同的主机之间也是有自己不同的主机标识的。
而路由器能够横跨两个子网也就意味着路由器一定是具有两个IP地址的(甚至于是两个网卡)。否则如果路由器只有一个IP地址,那么就没有路由的功能了。 路由器的两个IP地址都要和对应子网中其它主机的网络号保持一致。在同一个子网中不同的主机使用主机号进行划分。而在不同子网中的两个相同主机号的主机,使用网络号进行划分。
由此路由器就能够找到处于不同子网中的目标主机,然后将报文机进行发送。
这里需要知道一件事情,如果构建出了一个子网,那么在同一个子网中的所有主机的网络号都是一样的。
这里在说明一个知识,只不过这个知识是建立在网络是公网的情况下说明的。对于子网之后会说明。
这里首先需要知道的是,某一个地区的网络并不是一开始就存在的。例如我家中的网络并不是一开始就存在的,而是我去了一些运营商的线下店。这些线下店现在已经很少了。然后我的父母就找这些运营商买了路由器,网线什么的,让线下店的工作人员在我家装了一个网。
这里需要说明的就是网络并不是一开始就有的,而是我国大力推动才有了现在的规模。各种策略(光纤入户,网络下乡等等策略)。当我父母要装网的时候很多专业的知识我父母都不需要管,这些工作人员会自己装好。
因为我家中的路由器是运营商安装的,所以我家中的路由器一端一定是直接连接到运营商的网络。所以我家中的路由器已经横跨了外网了。
而现在的路由器使用的都是无线网(台式机也可以插网线),其它机器连接上wifi之后就能够上网了。
到这里就可以说明了,路由器有一个重要的功能一直在被忽略那就是构建子网。
在一个子网中每一个主机都有自己的IP地址而IP地址中的主机标识就是由路由器构建的。我现在想让我的电脑上网,但是我的电脑没有IP地址就无法上网。而一旦我连上我家的路由器的WiFi就有了IP地址,就可以上网了。所以路由器所谓的构建子网:
当然这个IP地址和公网中的IP地址是不同的。IP地址也是有不同的类别的(公网IP和内网IP)。所以当一个子网中的主机想要上网首先就要给路由器发送申请,然后路由器会分配一个IP地址给这个主机这个主机才能成为这个子网的一台主机才能够进行上网。
总结:路由器不仅能够转发报文还能够构建子网
既然要管理IP地址这个管理就需要路由器中准备好对应的策略去进行管理,所以在路由器中也是存在一个简单的应用层协议DHCP,路由器用来进行IP地址的管理。有了协议也就能够保证在同一个子网中不同的主机使用的是不同的标识号。这个协议能够自动的对加入的节点进行自动的分配主机标识号。但是DHCP是一个应用层的概念但是路由器不是工作在IP层的机器。原因就是科技发达了现在的设备不只能够进行简单的路由转发了/路径选择了。还可以为我们做很多应用层的工作,比如使用路由器的IP地址输入到浏览器中就可以看到下面的界面
然后你输入路由器后背的一些信息就可以对你家的WiFi进行管理。
而这里我输入的IP地址使用的是http协议而不是https协议。这不是web的功能吗?当登录就可以去配置你家的WiFi密码名称等等信息。由此可以看到路由器的功能是很强大的,不仅可以支持DHCP,http协议也是支持的,甚至可以在内部存在一些小型的数据库。所以虽然路由器的主要工作在网络层,但是路由器不止可以工作在网络层。以上只是为了说明:IP地址分为两个部分网络号+主机号,以及重新认识一下路由器。
在过去对于IP地址是进行了以下的划分方式的:
为什么要进行分类呢?首先之前已经说过了现在的IP地址已经不足了。而对于这种全世界有效的东西,都可以称之为资源:例如石油,天然气(有用且有限),那么这个东西一定是大家争抢的对象。如果这个资源被其它人占据完了,那么其它国家想要如公网就很困难了。所以对于IP地址一定要有一种分蛋糕的认知。所以对于IP地址一定要划分出来,由此划分给不同的人。例如虽然韩国的网络基础建设很好,但是人口少,分配的IP地址自然不会太多。而我国不仅网络基础建设好,人口也多,所以分配的IP地址自然也多。
所以在全球来看IP地址是一种资源,需要划分给不同的人,组织,机构,政府和地区的。由此就产生了上图中将IP地址分类的划分方案。
这里说明一种A类网络
最高位为0其它类型就是其它的网络。然后A类网络可以分成7位的网络号,和24位的主机号。所以A类网络一共会有2^7个,每一个A类网络中承载的主机数都是2^24次方个主机。其它的网络类直接看图。A类网络前1个比特位是固定的。B类网络前两个,C类三个。D类4个,E类5个。由此就将IP网络号划分为了不同的类别。不同类的网络中IP个数也是不同的:
A类2^7个,B类:2^14个,C:2^21个。
假设一个学校中的人有30000个,那么这个学校就适合申请B类网络因为B类网络的主机号为2^16次方允许2^16次方个人入网。这只是一个B类网络能够承载的人数,而B类网络的个数是2^14个。
这样的话对于B类网络00001可以给一个学校,0002可以给另外一个学校。因为B类网络一共有2^14次方个就可以给这么多个组织或者人使用。但是这种划分方式的局限性很快就显现出来了。因为大部分的机构都想要申请B类,为什么呢?因为C类不够而A类又申请不到。但是就算一个组织申请到了B类网络但是实际在架设网络的时候真的能够有2^16个主机去到这个网络中吗?很明显全满的可能性是很少的,这样不就造成了IP地址的浪费了,之前就已经说过了IP地址不足了,如果在存在这样浪费不就让IP地址不足的问题更严重了。
那么我家在申请网络的时候怎么没有这种问题呢?因为要考虑这些问题的,不是我们老百姓,我们也申请不到,使用申请这些的一般都是运营商/一些大型组织。
总结就是申请这些类别网络都是运营商需要考虑的问题。因为上面的那种划分方式很浪费IP地址由此就产生了一种新的IP地址的划分方式:
上面说的这四个点是什么意思呢?举两个例子:
上面的这个IP地址和子网掩码进行按位与就能够得到网络号。
此时在这个子网中的主机号也就就可以从0到255了。
那么为什么要做这样的事情呢?
首先子网掩码是一串0和1的组合。现在假设一个组织申请到了B类网络但是B类网络的主机号对于这个组织来说有点太多了,这个组织只需要使用到主机号中的8位,其它的位压根就用不到。此时就可以设置子网掩码为255.255.255.0.这样有什么好处呢?这丫昂就能让前面的16位网络号不变,而将中间的8位作为网络号去使用。
这样之后能够做到什么事情呢?
现在某一个路由器使用的就是这一个B类地址:而在使用了子网掩码之后,这一个路由器下面就可以连接其它的路由器了(没有子网掩码之前都只能是一个一个的主机)
所有的这些路由器的前16位都是一样的,但是这里我使用子网掩码将主机号中的8位做成了不一样的。
下面使用了不同的数字当作这8位
由此就能够将一个大的子网让其能够内部去包含更多的子网了。
也就是将一个大子网的拓扑结构修改为了下面这样的:
但是这还只是简单的说明,之后会更加详细的说明。但是现在能够知道的是对于B类网络使用这种方式就能够再次进行分解了。根据不同的主机数。这样对于每一种不同类别的网络都能够通过子网掩码完成主机数少了增加主机数,主机数多了增加网络数。
所以子网掩码能够提高分类之后的网络的利用率。
对于子网掩码和划分先学习到这里:
这里先去学习一下下面的知识:
在IP地址中是存在特殊的IP地址的
这个知识很简单不多做说明,但是当IP地址中的主机地址全部设置为0就代表这个局域网了,但是刚刚不是一直再说公网吗?怎么又变成局域网了
私有IP地址和公网IP地址
在这个世界上IP地址一共存在2^32次方个,但能够在公网中使用的IP地址只是一部分:
没有交集全集就是所有的IP地址,如果现在某一个组织想要组网并且只用于局域网通信(那么理论上来说IP地址随意使用都是可行的)但是RFC1918规定了下面的规则
只要使用了上面的IP地址的主机都是使用私有IP的主机,否则就是全局主机。此时我的Windows连接的是路由器搭建的局域网,所以IP地址是192.168.xx,而我的云服务器,则不适应上面的范围,但是真实云服务器IP需要使用指令进行查询,并且查询到的IP也是内网IP,公网IP我是查询不到的。这也是为什么我要使用云服务器,因为云服务器是具有公网IP的,但是家中的路由器并没有公网IP。
到这网段划分是怎么做的问题已经解决了。还有网段划分是什么的问题,和为什么要进行网段划分的问题需要进行解决。
为什么要进行网段划分
使用一个现实的学校,一个学校内部存在很多个学院。
而在一个学校中一个学生的学号是经过精心的设计过的:
从图中就可以看到这个学号的划分比起IP地址的划分还要多一点,复杂一点,这里我想简单一点:
对于学号就是用院号+个人编组成(总共8个比特位)。这里的院号我使用三个比特位进行表示。每个学院一共存在32个学生
此时对于可以这么认为每一个学院都是一个局域网。只要在一个局域网中大家的网络号是一样的,主机号不同。
然后在每一个学院中都有一个该学院的学生会主席(学生会主席也有自己的编号)。
然后有一个计算机学院的学生张三(000 00010)
然后在理学院有一个学生叫做李四。上帝视角的我是认识他的。
这个就叫做每一个局域网中都存在主机,每一个局域网中都有自己的网络号,每一个子网的网络号都是不一样的。在同一个子网中对应的主机号也是不一样的。不同子网中主机号可能是一样的。
而每一个学院的学生会主席也是会自己拉一个群的。其中存在一个群主,这人也就是校学生会主机兼任院学生会主席。
此时张三捡到了一个钱包,钱包中有钱也有卡,还有一个学生证,但是这个学生证除了学号以外的信息都没有了,学号为01000100
但是张三不认识这个学号。张三是计算机学院的,一般情况来说自己是不认识理学院的学号的,张三能够知道这是一个学号,但是张三不知道这个010代表什么意思。虽然张三知道前3位代表的是院号。此时张三就动脑子了,虽然张三不知道这个010是哪个学院的,但是可以肯定的是这个学号一定不是计算机学院的。虽然张三不知道,但是在计算机学院这个群中一定有一个人知道这个010代表的是哪一个学院。这个人就是院学生会主席。它必须认识这个院号,不然这个学生会主席就失职了。
此时张三就将这个钱包拍了一个照发到群中@了一下这个学生会主席。
假设这个院学生会主席的业务能力非常强看到这个就知道这个学号是理学院的。此时这个学生会主席就可以将这个信息转发到学生会长所在的群中。然后@一下理学院的学生会主席。此时的这个理学院学生会主席除了要对各个学院的信息需要了解,也要对自己负责的学生进行了解。在看到这个信息的时候确认这个钱包是理学院的,并且知道了这个钱包是李四同学的。然后这个理学生会主席就将这个照片发送到了理学院对应的群中然后@了一下李四。当然在发送这个信息的啥时候可以把钱包的发现者张三的部分信息也带上(联系电话)。然后李四就可以联系张三了。此时就完成了将钱包的信息从张三路由到了李四这里。这种方式的效率是非常高的,因为当张三将照片发到计算机学院的群中时自己做了判断这个信息不是学院中的其它人的,就将这个信息直接交给了学生会主席。这就意味着直接一次就将计算机学院中的所有人直接排除了(一次判断,张三如果一个人一个人的去问,那么一次只能排除一个,但是只要转发给学生会主席一瞬间就能够排除一个学院的人)。
而学生会主席在学会主席的群中@理学院的学生会主席就相当于一次性将除了理学院以外的其它学院的人全部都排除了。理学院的学生会主席再将这个信息转发到理学院的群中@李四是为了排除理学院中除了李四之外的其他人。
所以学校中定义学号的划分原因就是便于定位任何一名学生。
这种划分方案就已经存在一点子网划分的概念了。
子网划分之后有一个优势:
为什么:因为子网划分后相同网络的主机号全部都在一起。
而在上面的例子中无论是张三还是学生会主席首先看的都是前三位看是否是属于当前学院的。而这个前三位数字就是目标网络。
而整个过程都是先根据目标网络进行路由的(选择学院),到达了目标网络之后再根据主机号进行的选择(在学院中选择学生)。由此就产生了上图中说明的那个优势。这也是为什么要具有子网划分的重要理由之一。当然要进行子网划分的理由还有其它的,但是这一个已经可以说明为什么要进行子网划分了。
私有IP地址和公有IP地址
之前说过我家中的网是通过路由器实现的一个小型的子网,由此即使我没有给运营商交钱我也能通过路由器背面的信息登录到路由器的管理页面。而之前也说过路由器是需要跨过至少两个子网的,我家的路由器跨过的另外一个网络就是运营商的网络。
在我国运营商常见的有三家:中国移动,中国联通,中国电信。现在我们能够使用便捷的网络,这背后是存在大量的机房,算力,服务器,数据库,储存等集合起来,由互联网公司给我们提供的一个小小的APP。现在我能够上网也是运营商花费了几十年的时间,给我国建立网络基础设施(建立基站,机房,铺设光纤)。正是这几十年的网络基础设施的建设,才有了现在的网络。这些基础设备的建设都是运营商做的。虽然运营商会扣我们的钱(前些年运营商是存在乱收费的情况的),但是认识一个事物要全面,运营商有坏的一面也有好的一面。现在我们见到的各种互联网公司都是没有做基础设施的建设的。不会出现一个互联网公司让工程师拿着镐头去地里面挖地,然后去铺设光纤/建立基站的。大型互联网公司最多能够做的就是搭建一下机房。可以说基础设施建设中的脏活累活都是运营商做的。这些脏活累活为什么这些大型互联网公司不想去做1呢(铺设光纤/建立基站/数据转化机房等等)?这些工作都有一个特点:前期的投资特别多,回报周期特别长。大部分的喜欢赚快钱的公司不想去做。那么三大运营商愿意去干吗?我认为他们也不想去干,但是我国的政府是在推动运营商去干的。(例如在偏远的山区建立基站,这件事本身大概率是会亏本的,但是运营商还是做了,这背后就一定是存在政府的大力推动)。当然即使是被政府推动去做的,但是这也是运营商的功劳。
还有一件事情:在我国智能手机刚刚发展的时候,流量费是很贵的,但是随着智能手机的发展流量费也变得越来越便宜。
那么是运营商想要让流量费变便宜吗?很明显不是,但是因为流量费如果不便宜就会导致很多人用不起网,所以政府必须要让运营商把脏活累活干了,并且还要让运营商把流量费变得越来越便宜。由此就让流量费变得越来越便宜了。正因为有了这些条件,所以才有了现在的互联网公司给我国的人提供的例如抖音,淘宝这样的服务。
那么这里还有一个问题,当你使用抖音的服务的时候,给我提供服务的是抖音啊,为什么我要将钱给运营商呢?因为运营商要赚他的钱,运营商要将自己投资的钱赚回来。
但是现在我们使用网络一个信息必须要经过运营商才能到达互联网公司。
那么能否绕过运营商直接到达互联网公司呢?答案是做不到,如果能够做到的话,我国的互联网公司已经能够在非洲都建立分公司了(不考虑其它情况)。正因为做不到,所以如果中国的互联网公司想要去到非洲,首先就是中国的运营商先去到非洲将基础的网络设施建立好/或者卖手机的先过去之后,互联网公司才能去非洲建立分公司。
既然我是运营商的客户,我的信息需要经过运营商的网络,而互联网公司的信息也要经过运营商的网络才能够到达用户,所以互联网公司也是运营商的客户。所以互联网公司每年也要给运营商交钱。
既然我国的运营商需要做这样的工作,那么国外的运营商也是一样的,也是要做这些工作的。所以说两个国家你的互联网在发展,我的国家我的互联网也在发展,发展的快还是慢就决定了自己国家的网络规模是多大的。
由此就能得到一个结论了,无论是我个人发送的网络报文还是互联网公司发给客户的网络报文都需要经过运营商。
正因如此在之前才会出现之前存在的一个url劫持的情况(我要下载天天动听,结果最后下载了一个其它的应用)。为什么能够做到呢?因为运营商能够读到我的报文。
这里再说明一个知识点:家用路由器其实是具有两套密码的:
一套是WiFi的账号名和密码,另外还有一套账号和密码这个的账号一般都是手机号。然后这一套账号和密码在运营商那里一般都是存在一个表记录的,这个表中记录了一堆这样的账号代码各家各户的路由器,而每一家都有自己的网费信息。当某一家的网费欠费了之后,运营商就能够精准的拦截某一家的所有的报文,由此就让某些人家上不了网了。没有欠费的人家发送的报文就不会被拦截。这就是为什么一旦欠费就无法上网的原因。
既然运营商可以因为欠费不让我上网,那么是否也能因为我访问某些非法的网站让我不能上网呢?这就是因为墙的存在,由此也就出现了很多翻墙的方法(所谓的翻墙我认为就是在欺骗运营商)。但是既然存在翻墙的方法,就需要知道所谓的墙在哪里呢?这个墙就在运营商内部。更加详细的信息后面会说明。
有了上面的认识就可以看下面的这张图了:
首先一个家用路由器横跨了两个子网一个是我家的子网另外一个就是运营商的子网。因为路由器横跨了两个子网所以一定会有两个网卡,两套网络标识。
所以一般由路由器构建的子网中这个路由器的IP称之为子网IP也叫做LAN口IP
例如上图中的192.138.1.1。然后运营商也有自己的子网。在运营商的企业级路由器构建的这个大子网中家用路由器也有一个IP,这个IP就是对外的WAN口IP。例如上图中的10.1.1.2。
此时我家的路由器和我邻居家的路由器就共同属于同一片子网(存在可能),此时10.1.1.3和10.1.1.2和10.1.1.1就在同一个子网。对于10.1.1.1这个路由器来说也是对接的两个网络内部就是上图中的网络对外对接的就是公网:
由此我的信息才能够通过公网发送到互联网公司,互联网公司也才能为我们提供服务。
这里我假设一下:我要发送一个信息hello(使用上面的这个图)
这个IP报文会从我的主机开始,我的主机会先判定这个信息要去的目标地址是122.77.241.3和我的这个主机很明显不在同一个网段。我的子网掩码是24
这里的IP/n中n意思就是子网掩码的二进制前多少位是全1后面就是0。这里也就是255.255.255.0(一个字节8个比特位,前3个比特位位全1就是255,后面为0)此时这个dstIP地址和这个子网掩码按位与之后发现无法配上。但是我并不知道这个信息要去哪里但是我很清楚的知道这个信息一定不是发给我这个网段中的其它主机的。
所以我这个主机只能将这个信息转发给路由器,路由器知道以后也会首先拿IP地址和子网掩码进行按位与知道这个IP地址要去的地方。然后路由器发现目标网络也不是当前这个网段中的其它路由器的某一个主机的IP。此时这个路由器就会将其发送给企业级别的路由器。这个路由器发现IP为122知道要去公网中,所以这个报文就是被直接推送到公网当中。经过公网的转发最后到达目标服务器。
此时这个报文就到达目标服务器了。但是这个报文的192.138.1.201这个IP是内网的IP,而内网IP不能出现在公网中。
为什么呢?
因为在不同的内网中是可能存在相同的IP的,例如上图中我和我邻居家的IP地址就是一样的。如果这个IP地址出现在公网中就会出现冲突。这也是为什么内网IP不能出现在公网中,除此之外还有一个知识点就是在不同的内网中是可能存在相同的IP的,即在不同的内网中允许出现重复的IP地址。既然可以出现重复的IP这就可以在一定程度上大大缓解地址不同的问题。因为允许重复就增加了IP地址的绝对上限。
那么我的数据是如何到达公网又是如何回来的呢?
这里先说发送,当我发送的信息的目的IP不是当前子网中的其它的主机然后交给路由器之后路由器会做一件工作
当然上面的工作是不完整的还需要使用路由器的其它工作一起配合(端口等)但是那些之后再去说明,这里先说IP。
例如上图的信息在发送到路由器之后src就会被修改为路由器的WAN口IP10.1.1.2。然后这个信息再往上传到上一个路由器的时候,这个路由器就认为这个信息是这个家用路由器给我发送的信息。然后运营商的路由器再对比之后,也要转发,也会修改src地址为这个运营商路由器的WAN口IP。
然后再将这个网络报文通过公网发送到目标服务器。
然后目标服务器就拿到这个报文了。然后这个服务器就会将响应信息通过这个src地址返回给运营商的路由器。
这种在发送信息的时候不断替换源IP地址的技术称之为NAT技术(网络地址转化)这样至少就保证了服务器发送的响应能够到达运营商的入口路由器处,但是之后呢?之后要如何回到我的原始主机呢?这个知识之后说明。
这里是先引入NAT技术。
下面思考几个问题:是不是从家用路由器出去之后就到公网了呢?(这里的公网也是运营商建设的)
不一定,大概率不是,出去之后到达的应该是运营商建设的一个更大的子网(也是内网只不过是一个更大的内网)[例如家用路由器的192开头的IP地址能够承载的主机数是不多的]。一方面是为了更好的计费,还有一个方面之后会说明。
所以真正的网络解决方案如下:
第二个问题:
我能否从我家的某一个主机直接给我的邻居发消息呢?(我家的路由器和邻居家的路由器在同一个子网中,不经过公网)。答案是不能,因为我要如何填写目的IP呢?如果是上面那张图中我邻居家的IP地址,那么路由器在判断的时候不就直接发送到当前子网中的另外一个主机上了。所以现在两个人要通过网络聊天都要通过外部的服务器提供服务(QQ,微信)。我和我的朋友都登录了微信,我和我的朋友都将信息转发给了微信的服务器,然后微信服务器才会将信息转发给我的朋友。主流的通信方案就是这种。
网络拓扑结构
到目前为止,我们已经知道了在网络的结构中是存在公网的。但是对于这个公网更多的信息我们并不知道。那么这个公网究竟是什么呢?
下面就来理解公网其实也就是理解网络的拓扑结构。
首先我们知道在公网中的ip地址是又2^32次方个的,这里我们以国家为单位去分配这些IP地址(现实情况分配更加复杂这里不做说明,现实中IP地址一般是有一个范围给一个国家的),
但是这个分布并不是一个国家就拥有一个连续的IP分布的
现在我们已经知道了存在内网IP以及公网,在内网中是允许IP地址重复的,那么这个内网和公网要如何联系起来呢?
下面我们就画一张图片去理解:
这些就是一个一个的国家(没有画完)
然后IP地址也就是32个比特位,全球的主权国家是有限的(不到200个),然后2^8 -1 =255所以使用不到8个比特位就可以将所有的国家进行编码。
然后美国人起步比较早,所以再给美国分配IP地址的时候:
美国的IP地址开头就是这个数字
使用这种方法就可以将IP地址中的前面这些位全部用来表示国家
然后所有国家的子网掩码都是8(前8比特位位为1,后面的24个比特位为0).
然后每一个国家都有一个路由器会和其它国家连接起来: 和上面说的学生会的例子是一样的。然后在美国有一个人想要访问我国国内的网站,在那个报文最后会被发送到我国的路由器上最后就会转到我国了。
到目前为止,我们要知道在宏观上IP地址是可以进行划分的,并且可以通过IP地址的开头知道这个IP地址是属于哪个国家的。
现在回到我国的视角上,现在可以知道的是我国的IP地址一定是以
开头的(同时子网掩码传递给下层是8,代表IP地址的前8位是不可改变的,代表的是国家)。然后下面我又假定我国的IP地址是按照省份(34个)划分的(但是现实并不是严格按照省份划分的,因为每一个省份的人口是不一样的)。然后又按照子网划分将这些比特位划分给不同的省份。这里再使用8个比特位去表示不同的省份。
对于不同的省份来说前8个比特位已经固定了就是(2.),然后又使用8个比特位来表示不同的省份,此时的子网掩码就变成了16,代表前面16个比特位已经不可改变了。然后每个省份之间也是具有自己的路由器的:(这些路由器和哪个国际路由器也是在一个网络中的)
此时省份之间要发送信息就可以通过这些路由器完成信息的发送。
然后陕西省中还有市,这些市也有自己的路由器,并且这个路由器和陕西这个省级路由器在一个公网中。对于这些陕西市中的路由器来说,IP地址一定是以2.1开头的。然后再从IP地址中挑选4个比特位来表示市区(子网掩码变成20),下面这些路由器和陕西这个路由器在一个子网中,因为这里选择的是使用4个比特位表示市区,所以西安应该是2.1.16.xx/20.下图画错了。
然后在西安有一个人发送了报文这个报文最后要去的目标IP地址为: 1.xx,转发到西安这个路由器的时候发现这个报文不在当前所在的公网中就继续往上发送给国家路由器,最后由国家路由器将报文发送给美国的路由器。
到达市区的时候32个比特位才被使用了20个还剩下12个比特位。
而其它的省份也是类似于这样的。
但是当拆到西安的时候只有12个比特位能够使用了而2^12次方才4000多台主机。并且全西安的人员不可能都在一个局域网中吧。此时在往下拆分就会发现IP地址不够了。
此时将IP地址拆分到这里就可以了。其它的国家和省份都没有画,如果画全了这个东西就是公网了。
此时如果再往下划分IP地址就不够了所以此时再往下就到达了私网的部分了,对于西安来说又分成了不同的片区。这里又使用IP地址中的两个比特位来表示(子网掩码就变成了22)。对于西安的后一个片区来说就变成了:
其中前16个比特位代表国家和省份,然后的8个比特位代表的是西安和西安的某一个片区。这里直接将西安和西安的片区(8个比特位当作一个数字来表示了就是20)所以此时西安的都一个片区中的某一个路由器的IP地址就是2.1.20.0/22(假设将西安就之划分为两个片区)
此时将这两个路由器和西安这个市的路由器划分在一起,然后在往下就是当地的运营商构建的网络,然后这个网络就能到达我的家中。然后假设现在我在家中发送一个报文这个报文要去的IP地址为2.3.2.1.将这个IP地址和子网掩码24按位与发现这个IP地址并不是我这个局域网中的IP地址。就将这个报文发送给了家用路由器,家用路由器将原IP地址做了替换,继续交给上层(也是做了按位与发现不是家用路由器所在的局域网中的)。此时就给到了西安路由器了,按位与之后发现网络部分为2.3.2和西安的2.1.16也是对不上的,就会继续往上交到了陕西的2.1开头的路由器。先拿子网掩码得到这个报文的dst为2.3(子网掩码为16)陕西是2.1不对。然后发现在省中云南的IP的网络部分就是2.3,就将这个报文交给了云南的路由器。此时就可以将报文转发过去了。所以现实的网络情况为上面是公网下面就是一个一个的局域网(我家中的局域网,运营商构建的局域网等等),所以我国的运营商在全国各地都会有自己的子网区域。
正因为有了这样特殊设计过的网络结构才能做到报文能够在各个省份之间互相转发。
所以就有了一种互联网公司和运营商合作的方法:运营商给大的互联网公司开放一些IP让互联网公司的路由器和运营商的路由器进行连接,此时互联网公司不就入网了吗?入网之后运营商的公网IP暴露出来之后,此时其它省份的人员也就可以使用这个互联网公司提供的服务了。
到现在为止我们就可以从宏观上简单理解了网络的拓扑结构,以及
理解了报文是如何在国家之间省份之间进行转发的。
下面还有一个信息
对于这个信息之后会进行测试,下面我们来看一个计算
最后的子网地址范围是如何计算出来的呢?因为子网掩码为255.255.255.240,所以进行按位与之后140.252.20是不会变的(按位与的规则是有则为0,双1才为1),所以而255.255.255代表前24个比特位全是1所以140.252.20是不会变化的。然后1就是让68和240进行按位与了:
最后计算出来的结果就是64,所以上图中的网络号就是140.252.20.64.对于32位的IP地址来说子网掩码有多少位是1呢?(就代表IP地址的前面多少位已经不能再改变了)244二进制位1111 0000 所以子网掩码就是前面28位全为1对于32位的IP地址来说,只有4个比特位用于组建内网。4个比特位也就是15。
而64+15 = 79,所以最后的范围就是从64到79。
网络IP的限制,之前已经说明过了全世界公网IP地址只有2^32次方个能够被使用(43亿左右),但是其中某些IP地址要用于组建内网,所以真正能够使用的IP地址也没有2^32次方个。而且IP地址是按照网卡的数量来进行配置的,而有的设备(交换机,路由器等)具有多张网卡,就会具有多个IP地址,如果在公网当中这样去搞的话,能够给普通人使用的IP地址就没有了甚至于组建公网都够呛。虽然子网掩码在一定程度上缓解了IP地址不够用的情况(提高了利用率)
所以为了解决IP地址不够的问题所以就有了下面的方案:
第一种方式也就是我家中的路由器给每一个连接上这个路由器的机器手动分配IP地址。
这种方案是很好的,但是要解决IP地址不足这个方案只是杯水车薪。
NAT技术这个技术就是允许不同的子网中出现重复的IP地址。也因此当一个子网中的主机要发送机器时,会先发送信息到达路由器,路由器做了IP替换之后,在发送这个报文给下一个路由器。也因为会发生IP替换所以对于一个主机发送的报文来说到达公网的时候,这个报文的原IP地址就不是我这个主机的IP地址了。这种技术因为允许了不同的子网中出现重复IP地址,所以很大程度的解决了IP地址不足的问题。
由此在互联网的末端使用的都是内网IP,而且IP地址可以重复,而在顶端进行报文的转发。这种方式是在全世界都有使用的,所以在全世界的范围内IP地址为:192.168.1.20的主机是上千上万的,但是因为有NAT技术这都是不影响的,但是到目前为止对于NAT技术,我都只知道怎么出去,对于一个报文如何回来我是不知道的。后面会进行说明。这也是当前解决IP地址不足的一个重要方法,除了这个以外还有一个解决IP地址不足的方法就是IPV6,这也是我国正在大力推行的一种方法(大力推动运营商去做基础设施的建设,网络费用降低)。但是因为IPV6和IPV4不兼容,如果要让所有机器都重新使用IPV6的话,会存在部分机器不好升级,所以要让这种技术更加广泛的使用是比较难的(其它国家不好推广),但是虽然我国无法推广到其它国家但是我国内的网络还不好推广吗?
因为公网我国已经无法改变了,所以就将公网当作基础设施建设使用起来。然后我国再要求互联网公司在组建机房的时候必须支持IPV6的网络,然后要求路由器厂商也要支持IPV6一方面也就是给互联网公司提供路由器功能。例如我家中的路由器/电脑也是支持IPV6的。
最后在说明一下下面这张图:
这张图是没有画全的(私网部分,在上图中我家的路由器只经过一个路由器就到达公网了,但是事实应该是在运营商的这一个路由器下还有其它很多的家用路由器,而这个运营商的路由器也应该是在一个大的子网当中的,然后再往上才是公网[当然详细的信息我也不知道,但是网络的大致结构是上图,但是真正的结构应该会更加的复杂],也正如此在运营商搭建的网络中路由器是分级别的,运营商路由器的功能为收集末端用户发送的信息进行信息的转发以及发送响应到各个末端用户)公网部分也没有画全。
最后在补充一些信息:
以上就是网络拓扑结构以及运营商的概念知识。
路由
报文在进行路由的时候需要知道IP等于目的网络+目标主机。所以一个报文在进行路由的时候都是先根据网络号先进行报文的跳转的。一个IP报文在进行路由的时候这个报文的网络号是如何进行确认的呢?是因为这个报文每经过一个路由器就会该路由器当中的特定条目对应的子网掩码按位与得到对应的网络号。所以一个报文经过路由器的时候是一跳一跳的不断选择网络的。
在IP报文中也有TTL字段说明这个报文能够在网络中经过多少跳数。而IP报文在一次次的跳跃的过程其实就是一次又一次查表的过程。
为什么这么说呢?
这个报文的发送就相当于问路:
在问路的时候够得到的答案无非就是三种:
第一种:被问的对象也不知道,被拒绝了,当然在网络这里不考虑这种情况,如果设计出的算法会进行拒绝说明这个算法是有问题的。 所以在网络这里不需要考虑这种情况。
第二种:被问的对象告诉你下面要怎么走,但是并一定按照这么走到终点就是你要到达的地方。在网络这里就是告诉了我下一跳要去往哪里。或者这个人不知道,但是他告诉你某一个人可能会知道你下面要怎么走。在网络当中就相当于这个主机不知道或者地方在哪里,但是将报文路由到了这个局域网的路由器那里。这个就叫做默认路由
第三种:你问的这个对象就是你要去的这个目的地的人(意思就是你已经到达目的地了)。对于报文来说就是已经到达了目标网络了,此时就需要询问这个对象(路由器)某一个主机在哪里了。此时路由器再告诉这个报文要怎么跳。
所以当一个报文再路上发送的时候都是以目标网络问路由器的,当到达目标网络之后(其实就是到达了这个目标网络的入口路由器)再询问这个路由器我要去的详细主机(也就是这个报文要去的目标主机)。
总结过程就是:
当到达目标网络后询问主机最后到达目标主机。
那么为什么上面要说查表呢?
因为:
这个路由表不止路由器拥有主机也拥有,那么我本机的路由表是什么样子的呢?
在Linux中使用指令:
route
就可以进行查询.
上面就是我当前主机对应的路由表当然在Windows中也是可以查询的,使用命令行:
主要还是来看Linux中的路由表其中的Destination就是你要去的目标网络,Gateway代表的是我的下一跳Genmask就是子网掩码 Flags代表的就是标记位。Ref和Use这里不说明。Iface说明你要将信息转发出去你要使用的接口。
因为我的这个表并不是路由器的路由表,我这个路由表只能判断这个信息是否是发送给本地的 ,或者是和本机在同一局域网中的网络。
因为我的这个表并不是路由器的路由表,我这个路由表只能判断这个信息是否是发送给本地的 ,或者是和本机在同一局域网中的网络。
假设这里要去到一个IP地址为120.1.2.3的主机上,那么在查询这个路由表的时候是如何进行查询的呢?
首先先让条目信息指向路由表的第一个条目:
在这一个条目中有一个子网掩码,那这个子网掩码和IP地址进行按位与。此时就拿到了这个报文要去到的目标地址。得到这个报文要去到的IP地址为120.1.0.0。然后拿这个地址和Destination中的地址进行对比发现不相等。说明这个条目去到的目标网络和这个报文要去到的目标网络是不符合的,所以此时就继续扫描路由表当中的下一个条目。
拿新的子网掩码和IP地址进行按位与
发现要去到IP地址为
和Destination中的地址对比发现也是不对的。最后一个IP地址是网关。这里暂时不查,到这里说明本地的表已经查询完成了,发现这个路由表没有匹配的,就能去匹配第一个了:
因为这一个的子网掩码为全0。此时将IP地址按位与之后得到了0.0.0.0。然后就可以和default进行匹配,这个东西也就是默认缺省路由。
这个缺省路由的下一跳就是_getway这个最后就会变成当前子网中的路由器的IP地址。此时就将这个报文推送到了局域网路由器中
如果某一个IP地址在经过子网掩码按位与之后发现和Destination是一样的就会转发到对应的路由器下。不相等就去检测下一个,如果查不到就缺省路由。
当然上面哪个路由表也不太便于观察,下面这张路由表更加便于进行观察:
现在回到我们画的公网的拓扑图上:
这些国家级别的路由器之间也是会进行信息交换的,例如如果在美国某一个人发送的报文目标地址为2.0.x.x交给美国的路由器之后美国的路由器就知道了这个报文需要交给中国的报文(通过查询路由器中的路由表),也就是在美国的这个路由器的表中具有其它国家的标识IP地址(中国是2.0,俄罗斯是3.0等等当然这些都是在我假设的这个网络拓扑图中,现实并不是这样的,但是在现实中一个发送给中国的报文被美国的路由器收到了,也是知道要转发给中国的路由器的。对于其它的国家路由器都是一样的)
国家级别的路由器是这样的,省级别的路由器并不是配置好自己的后就完了,这些省级别的路由器之间可以进行IP的交换。这样就可以让每一个路由器都知道当前所在的局域网中其它路由器的信息。知道了这些信息之后,当收到报文之后就可以查路由表让报文进行正确的跳转。
总结就是处在同一个局域网中的主机是可以直接进行通信的。通过局域网中路由器的通信就能够实现让某一个局域网中的所有路由器都知道当前局域网中其它路由器的入口和子网掩码。由此就能实现当路由器收到报文之后判断是否是我这个局域网中的其它主机的报文(也就知道了这个局域网中的出口路由器)。
对于路由表的生成也是存在算法的:
也正因为有了这个路由表才能实现报文从一个主机不断的跳转最后跳转到另外一个主机上。
现在回到这张图上:
当从主机A发送报文的时候,主机A其实已经知道了接收方的IP地址了。正因为有了接收方的IP地址,所以当报文经过路由器的时候才能正常的查询路由表。
所以当一个路由器在进行报文转发之前就已经知道了,和自己彼此相连的另外一个子网的入口路由器了。此时就能够通过拿着目的IP地址每经过一个路由器就去查询路由表,就知道这个报文下面要条状的位置了,经过不断的跳转就能够完成将报文从一个主机发送到另外一个主机的任务。
之前说过TCP在三次握手建立连接的时候,不就是在发送报文吗?三次握手就注定了IP报文要交换三次。当一个TCP报文经过IP层百年城IP报文后经过上面的跳转到达目标主机才完成了一次,目标主机再发送回一个IP报文回到我的发送主机,这样才完成三次握手(SYN和ACK被目标主机一起发送回来了)。所以之前在应用层看起来很容易完成的一件事情,在网络层是需要经过多次跳转的。
所以之前在TCP说过的滑动窗口:滑动窗口支持TCP层发送大量的报文,这些报文在IP层都会被包装成为IP报文。然后这些独立的报文就在网络中一跳一跳的最后到达目标主机。所以对方收到报文之后,如果是UDP就不管直接往上交,而TCP则需要将这些报文交给TCP层,TCP层要通过序号对这些报文进行排序,再链接到Recv_queue中此时再交给上层上层就得到了。这些工作在TCP层看起来是很容易的但是在IP层做了非常多的工作。
IP报文的最后三个字段
对于这个报文的第二行还没有进行说明。下面就来说明
首先我们知道网络是分5层的(下图没有画硬件层):
TCP可以向底层发送多个报文,由此网络层也就可以包装出多个报文,但是在数据链路层存在一个规定:
至于原因在讲解数据链路层的时候进行说明。一般来说上层交下来一个报文就会封装一个数据帧。
这个不能太大,到底是多大呢?在Linux中可以通过
ifconfig指令查看,其中有一个字段叫做mtu
这个eth0就是其中一个网络接口的名字。未来网络收发数据都是通过这个eth0来进行收发。mtu可以理解为最大传输单元,这里单位为字节,所以数据链路层要求的大小就是1500字节。之后会说明在数据链路层也会具有自己的报文。这个1500就代表IP层交给数据链路层的有效载荷不能超过1500字节。必须小于等于1500字节,这样我的数据链路层才好将数据发送出去。
如果网络层还是给数据链路层发送超过了1500字节的数据呢?例如IP层就给数据链路层发送了3000字节的信息。此时数据链路层就无法处理,由此就逼着网络层IP层必须具有一个功能:分片与组装。什么是分片呢?例如这个数据报文是3000的那么IP层就可以将这个报文分解成2片或者3片。分别交给数据链路层。此时虽然tcp层发送的只是一个报文,但是经过IP层分片之后到达数据链路层就变成了三个报文了至于组装就是将多个报文合成为一个完整的报文。分片在发送方的IP层做,组装就在接收方的IP层做。总结就是数据链路层是跑腿的,数据链路层提出了要求所以上层必须去遵守。
对于应用层和传输层来说是感知不到底层对报文进行了分片处理的,对方的TCP层在接收报文的时候接收的就是一个报文。应用层在接收的时候也是一个报文。所以分片和组装是在IP层内部做的,对于上层是不影响的。
由此就能知道了第一点:当上层将数据交给下层之后,下层要对数据做什么上层是不会管的,只要下层能够保证将任务完成即可。
第二点:首先分片一定是不好的,
如果分片了本来只用发送一次报文就能完成的任务现在要发送两次/三次报文。这就意味着如果在这些分片中有一个分片丢了,接收方在组装的时候就无法组装了。由此就只能进行重发那么在重发的时候是将丢失的一些小片进行重发还是将或者IP报文都进行补发呢?
当IP层无法组装完成时,IP层就是直接将这个无法组装的报文进行丢弃。只能要求发送方重新发送整个报文。所以分片发送就会导致丢包的概率提升。所以分片为什么不好呢?就是因为间接的提高了丢包的概率。一 个报文被分片了,一个分片报文的丢失就会导致整个报文的丢失,由此就导致了丢包的概率增大。虽然传输层会进行重发,但是这样就会降低发送效率。并且对于已经收到的分片报文还要进行发送等于会浪费cpu的算力,内存等等资源。这还是TCP具有重发的机制,如果是UDP那么对于通信双方来说都会降低发送/接收效率。
那么要如何做到尽可能的不分片呢?
就只能要求TCP单次发送的数据量不要太大。这也是为什么在讲解TCP的滑动窗口的时候,为什么TCO不直接将滑动窗口中可以发送的信息直接弄成一个大报文直接发送出去呢(因为是流式传输这样是可以的),就是因为数据链路层要求了单词接收的上层的报文的有效载荷不能超过1500字节。将其分成一个一个的数据段就能够尽可能的减少网络层的分片。传输层必须分片也是一种隐形的可靠机制。
所以当传输层读取到1460个应用层的数据的时候,加上自己20字节的报头(1480)交给IP层,IP层在加上自己的20字节报头(1500)交给数据链路层,此时就刚好不会进行分片。所以这个1460字节就被叫做TCP传输数据的最大段尺寸。简称MSS。
在mac帧这里叫做mtu,这个MSS之前已经见过了。对于UDP来说也是这样,由此IP层就不会进行分片了。
下面要说明的这三个字段就是为了支持双方进行分片和组装的。
每一个IP报文都有自己的标识,这个标识不是为了区分有序性,有序性有TCP报文去完成,这个标识只是为了保证唯一性。并且如果某一个报文被分片了那么这些分片报文的标识一定是相同的。
下面是是3位标志:
上图中标志位3写反了,应该是最后一个分片设置为0,其它分片设置为1
第二位:如果你给我的报文超过了1480字节还设置了这个字段,那么IP模块就会直接将这个报文丢弃。一般这个禁止分片选项都是关了的。
第三位:就是更多分片的意思,这个意思就是如果这个报文被分片了,那么最后一个分片报文的这个标志位为0其它分片报文的这个标志位为1。就相当于c语言的字符串最后一定是以\0为结束标志位的。在组装的时候这个标志位很重要
最后就是13位片偏移:
对于上图中描述8的问题之后会进行说明。
举一个例子现在一个报文3000字节。分成两片第一片的片偏移就是0。第二片就是1500。
这里存在错误,之后会举一个正确的例子。讲解一下上面会乘上8的原因就是一个报文最多的字节数也就是2^16次方,而13位片偏移能够表示的最大长度就是2^13次方,乘上一个8就能够让13位片偏移表示2^16次方。这里我就不考虑8了。
下面我们就来模拟一次分片和组装。
模拟分片和组装
假设这里的IP报文是3000字节的(去除IP报头20字节上层床底下来的有效载荷就是2980字节)
那么这个IP报文如果要分片的话需要分成几片呢?肯定不是2。因为
这3000字节的数据已经具有了一个IP报头了,所以直接将3000字节中的1500字节拿出来作为第一个分片报文直接传递下去
然后第一个1500字节大小的报文在ip报头这里就需要填充三个字段:
16位标识标识唯一值,3位标志因为后面还有分片所以是001。因为这个分片报文是从原始报文的0开始的所以13位片偏移就是0.
然后是第二个报文,此时这个报文还剩下1500字节,但是这1500字节确实数据是没有有效载荷的。所以在传递给下层的时候,只能从1500字节中拿取1480个字节的数据。然后添加上IP报头然后交给数据链路层。
然后就是这三个字段的填写了:
16位的标识不用说和第一个分片报文时一样的,而3位标志位因为这一次分片之后后面还存在分片所以还是001。最后就是13位片偏移了。因为这一个分片报文是在上一个个分片报文的1500字节后开始添加的,所以第二个分片报文的13位片偏移就是1500/8。
下面就是最后一个分片报文了:
原始的整个报文还剩下20字节的数据。这20字节的数据拿下去增加IP报头,在这个报头中的三个字段的值就是: 16位标识依旧是和前面两个分片一样的,3位标识因为这个报文后面没有分片报文了所以这里就是0。最后就是13位片偏移了:
第一个分片报文的有效载荷位1500,第二个分片报文为1480(需要去除20字节的IP报头这个报头是新增的)
所以这个分片的13位片偏移就是1500+1480 = 2980。但是这个数字需要保证能够整除8否则就需要将第二个分片报文中的部分数据拿到这第三个报文中。2980这个数据就不能保证被8整除,就需要从第二个分片报文中拿取部分数据到第三个报文中。保证这最后一个分片报文的13位片偏移能够被8整除。对于这个在os中是有算法去进行计算的
在分片这里唯一的一个坑就是:
下面就是进行组装了:组装需要考虑下面的问题:
首先如果这个三个分片接收方一个都没有收到,那么接收方什么也干不了。
假设接收方收到了第一个报文,接收方因为知道了这个分片中的更多分片字段被设置了就知道这一个报文并不是一个完整的报文。
所以如何知道这个报文分片了呢?
那么如果第一个和第二个报文丢失了,但是最后一个报文被接收了呢?此时更多分片的标志位为0。
更多分片为0只有两种情况:第一种这个报文是一个独立的报文,要么这个报文是分片之后的最后一个报文,此时接受方只需要再去看一下13位片偏移,因为如果没有进行分片那么13位片偏移一定是0。
进行了分片那么或者13位片偏移一定不是0。这样接收方就能够判断某一个接收到的报文是否被分过片了。
经过这两层就知道某一个报文是否经过分片了。
现在接收方已经知道某一个报文是否经过分片了,因为所有分片报文的16位标识都是一样的,此时的接收方只需要做一件事情。
到这里第一个问题就搞定了,第二个问题:接收方如何判断某一个分片报文已经收取完全了呢?
这里就需要知道第一个分片的13位片偏移加上这个分片报文的长度就是下一个分片报文的13位片偏移。
第二个分片报文的13位片偏移+自己去除新增报头的有效字节大小就是最后一个报文的13位片偏移。
并且接收方能够确定收到了第一个分片报文,因为第一个分片报文的13位片偏移为0。同时也能确认收到了结尾分片,因为结尾分片的3为标志为0。由此就能够确认开头和结尾的分片是否已经收到了。
确定了开头和结尾中间的报文丢没有我是否能够确认呢?当然可以
方法如下:
进行排序之后如果发现某两个区间无法对上了,代表某一个分片报文丢失了,直接丢弃所有的已经收到的分片报文让对方重新发送。
所以接收方也能够确认自己将分片报文收集完全了。
将前面两个问题弄懂最后一个问题的答案也就出来了。
只要能够接收方收集全了分片报文,在对分片报文按照13位片偏移进行排序之后就能够按照排序的结果对所有的分片报文进行组装了。
以上所有计算13位片偏移都是没有进行除8检测的(为了便于理解)。
希望这篇博客能对您有所帮助,发现了错误欢迎指出。
相关文章:
网络基础(4)IP协议
经过之前的学习对传输协议的学习,对于传输协议从系统底层到应用层对于socket套接字的学习已经有了一套完整的理论。 对于网络的层状结构,现在已经学习到了应用层和传输层: 在之前的学习中,通信的双方都只考虑了双方的传输层的东西࿰…...
124. 二叉树中的最大路径和【 力扣(LeetCode) 】
文章目录 零、原题链接一、题目描述二、测试用例三、解题思路四、参考代码 零、原题链接 124. 二叉树中的最大路径和 一、题目描述 二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径…...
echarts:简单实现默认显示两柱子折线,点击按钮后显示新的柱子
问: 用echarts实现:默认显示两柱子折线,点击“税率”按钮,显示税率柱子,之前的两柱子折线消失 回答: <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8…...
视频里的音频怎么提取出来成单独文件?音频提取照着这些方法做
在数字时代,视频与音频的分离与重组已成为日常需求之一。无论是出于制作背景音乐、保存讲座内容,还是编辑播客素材,提取视频中的音频并将其保存为单独文件都显得尤为重要。视频里的音频怎么提取出来成单独文件?本文将详细介绍几种…...
Excel——宏教程(精简版)
一、宏的简介 1、什么是宏? Excel宏是一种自动化工具,它允许用户录制一系列操作并将其转换为VBA(Visual Basic for Applications)代码。这样,用户可以在需要时执行这些操作,以自动化Excel任务。 2、宏的优点 我们可以利用宏来…...
C++中的std::tuple和std::pair
在C标准库中,std::tuple和std::pair是两种极具实用性的数据结构,它们都具备存储多个元素的功能,但各自有其独特的适用环境和特性。本文旨在深入探讨这两者之间的区别,并阐述在不同应用场景下应如何合理选择使用。 一、基本概念 s…...
引力搜索算法
引力搜索算法过程,包括了初始化、适应度评估、质量计算、加速度计算、更新速度和位置的一些步骤。 import numpy as np import random as rd from math import exp, sqrt import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from matplotli…...
【时间之外】IT人求职和创业应知【35】-RTE三进宫
目录 新闻一:京东工业发布11.11战报,多项倍增数据体现工业经济信心提升 新闻二:阿里云100万核算力支撑天猫双11,弹性计算规模刷新纪录 新闻三:声网CEO赵斌:RTE将成为生成式AI时代AI Infra的关键部分 认知…...
Linux的目录结构
/ ├── bin # Binary - 存放用户可以直接使用的基本二进制可执行文件 ├── sbin # System Binaries - 存放系统管理员专用的二进制可执行文件 ├── usr # Unix System Resources - 存放用户使用的软件和库文件 │ ├── bin # Binary - 用户级应用程序…...
python: generator IDAL and DAL using sql server 2019
其它数据库也是一样的思维方式 create IDAL # encoding: utf-8 # 版权所有 2024 ©涂聚文有限公司 # 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎 # 描述: # Author : geovindu,Geovin Du 涂聚文. # IDE : P…...
命令执行简单
前言:小迪安全2022第一节反弹shell,小迪用的是两台都是云服务器,没有服务器可以在自己的主机上搭建也是可以的,主机上搭两个网站 思路:生成一个木马文件,下载到本机,然后利用本机上传到目标主机…...
【一句话经验】亚马逊云EC2 ubuntu24.04.1开启ROOT登录Permission denied (publickey)
按照常规的方法SSH登录会一直报错: Permission denied (publickey) 因为亚马逊云的默认配置不是在/etc/ssh/sshd_config,而是在引入的文件里了,所以在instance控制台输入这行命令来解除登录限制: sudo sed -i s/^PasswordAuthe…...
百度智能云千帆大模型平台引领企业创新增长
本文整理自百度世界大会 2024——「智能跃迁 产业加速」论坛的同名演讲。 更多大会演讲内容,请访问: https://baiduworld.baidu.com 首先,跟大家分享一张图,这个是我们目前大模型应用落地的场景分布。可以看到,大模型…...
【Linux】深入理解GCC/G++编译流程及库文件管理
目录 1.背景知识 2.gcc/g如何完成编译 (1) 预处理(进行宏替换) (2) 编译(生成汇编) (3) 汇编(生成机器可识别代码) (4) 链接(生成可执行文件或库文件) (5) 总结 (6) 函数库 …...
【Unity基础】对比Unity中两种粒子系统
在Unity中,Particle System和Visual Effect Graph (VFX) 都是用于创建粒子效果的工具,但它们的设计目标、使用场景和功能特点有所不同。以下是详细对比: 1. Particle System 特点 传统粒子系统,Unity自带的模块化粒子特效工具。…...
琐碎笔记——pytest实现前置、后置、参数化、跳过用例执行以及重试
pytest的fixture中文介绍可参考(不过文档稍微有点老): https://www.osgeo.cn/pytest/fixture.html#what-fixtures-are pytest各个作用域的fixture scope “function” 可作用于每个用例 fixture使用的声明放在类定义前面,类中的…...
C# 深层副本与浅层副本 深拷贝与浅拷贝
C# 深层副本与浅层副本 数据复制是编程中的重要任务。 对象是 OOP 中的复合数据类型。 对象中的成员字段可以按值或按引用存储。 可以以两种方式执行复制。 浅表副本将所有值和引用复制到新实例中。 引用所指向的数据不会被复制; 仅指针被复制。 新的引用指向原始…...
CH06_Lambda表达式
第6章:Lambda表达式 本章目标 为什么要学习C#编程语言 了解C#相关常识 C#开发工具Visual Studio安装 掌握C#程序的开发步骤 掌握C#的注释 掌握C#的常用转义符 本章内容 lambda表达式演变史 C# 匿名函数的演变历史可以追溯到 C# 语言的不同版本,…...
大模型本地部署实践:Ollama+Open-WebUI(MacOS)
目录 什么是Ollama Ollama安装 对话界面可视化?Open-WebUI! 安装Open-WebUI 什么是Ollama Ollama是一个为简化大语言模型本地部署与交互的开源框架。它提供了用户友好的接口,帮助开发者和模型爱好者在没有依赖外部API的基础上高效地运行、…...
JavaScript——DOM编程、JS的对象和JSON
一、DOM编程 DOM(Document Object Model)编程:就是使用document对象的API,完成对网页HTML文档进行动态修改,以实现网页数据,和样式动态变化效果的编程。 (一)DOM获取元素的多种方法 1.查找元素的函数 getElementById("id值…...
SIMCom芯讯通A7680C在线升级:FTP升级成功;http升级腾讯云对象储存的文件失败;http升级私有服务器的文件成功
从事嵌入式单片机的工作算是符合我个人兴趣爱好的,当面对一个新的芯片我即想把芯片尽快搞懂完成项目赚钱,也想着能够把自己遇到的坑和注意事项记录下来,即方便自己后面查阅也可以分享给大家,这是一种冲动,但是这个或许并不是原厂希望的,尽管这样有可能会牺牲一些时间也有哪天原…...
OSRM docker环境启动
命令一把梭 wget https://download.geofabrik.de/asia/china-latest.osm.pbf docker pull osrm/osrm-backend docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-extract -p /opt/car.lua /data/china-latest.osm.pbf docker run -t -v "${PWD}:/data&q…...
Vue3 动态获取 assets 文件夹图片
我真服了Vue3 这个老六了,一个简单图片src 赋值搞得那么复杂. //item.type 是我遍历类型的类型参数 <img alt"吐槽大会" :src"getAssetUrl(item.type)" /> 基于 Vue2 的Webpack 处理,还不错,可以用/ 这种绝对路径,可以接受,虽然多了个require很不爽…...
<项目代码>YOLOv8 草莓成熟识别<目标检测>
YOLOv8是一种单阶段(one-stage)检测算法,它将目标检测问题转化为一个回归问题,能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法(如Faster R-CNN),YOLOv8具有更高的…...
代码随想录算法训练营第五十一天|Day51 图论
岛屿数量 深搜 https://www.programmercarl.com/kamacoder/0099.%E5%B2%9B%E5%B1%BF%E7%9A%84%E6%95%B0%E9%87%8F%E6%B7%B1%E6%90%9C.html 思路 #include <stdio.h> #define MAX_SIZE 50 int grid[MAX_SIZE][MAX_SIZE]; int visited[MAX_SIZE][MAX_SIZE]; int N, M; …...
uniapp 自定义加载组件,全屏加载,局部加载 (微信小程序)
效果图 全屏加载 页面加载使用 局部加载 列表加载里面使用 使用gif html <template><view><view class"" v-if"typeFullScreen"><view class"loading" v-if"show"><view class""><i…...
STM32完全学习——系统时钟设置
一、时钟框图的解读 首先我们知道STM32在上电初始化之后使用的是内部的HSI未经过分频直接通过SW供给给系统时钟,由于内部HSI存在较大的误差,因此我们在系统完成上电初始化,之后需要将STM32的时钟切换到外部HSE作为系统时钟,那么我…...
Github 2024-11-16Rust开源项目日报 Top10
根据Github Trendings的统计,今日(2024-11-16统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Go项目1Python项目1Lapce:用 Rust 编写的极快且强大的代码编辑器 创建周期:2181 天开发语言:Rust协议类型:Apache License 2.0St…...
CH03_反射
第3章:反射 本章目标 掌握反射的原理 熟悉反射的基本运用 本章内容 反射是什么 C# 编译运行过程 首先我们在VS点击编译的时候,就会将C#源代码编译成程序集 程序集以可执行文件 (.exe) 或动态链接库文件 (.dll) 的形式实现 程序集中包含有Microsoft …...
vue2侧边导航栏路由
<template><div><!-- :default-active"$route.path" 和index对应其路径 --><el-menu:default-active"active"class"el-menu-vertical-demo"background-color"#545c64"text-color"#fff"active-text-col…...
wordpress 登陆后跳转/seo数据是什么意思
第一步:找到下图两个组件,卸载。第二步:NuGet下载下图组件。第三步:在连接数据库OnConfiguring方法处,做如下修改:protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){var co…...
湖北做网站的公司/如何做好推广工作
一、No module ‘xformers’. Proceeding without it. 这是因为没有安装xformers导致的。 解决办法: 在webui-user.bat文件这添加一行: set COMMANDLINE_ARGS--xformers如下图所示: 试着点击webui-user.bat,看能否下载ÿ…...
免费手机网站app/网络推广员是什么工作
点击上方“Python大本营”,选择“置顶公众号” Python大本营 IT人的职业提升平台Python经过了几十年的努力才得到了编程社区的赏识。自2010年以来,Python得到了蓬勃发展,并且在2019至2020年更是经常霸占每月PYPL编程榜榜首位置!但…...
人气最旺的传奇手游/厦门seo排名外包
在应用有frameset或者iframe的页面时,parent是父窗口,top是最顶级父窗口(有的窗口中套了好几层frameset或者iframe),self是当前窗口, opener是用open方法打开当前窗口的那个窗口。 window.self 功能&#x…...
赣州网络招聘/百度seo优化技术
2019独角兽企业重金招聘Python工程师标准>>> 后台编辑器代码是没有高亮显示的,但是代码会有特效 1.后台需要加载prettify.js和prettify.css, 还有页脚填上<script>prettyPrint(); </script> <script charset"utf-8&qu…...
布吉附近做网站/搜索引擎优化举例说明
1.1 Docker 磁盘扩容 默认情况下,物理机下创建的docker容器的空间是10G(虚拟机下创建的docker容器空间就是虚拟机的空间)。 Docker容器动态扩展的优点: 1)不需要修改docker配置,不需要重启docker服务&#…...