T04BF
👋专栏: 算法|JAVA|MySQL|C语言
🫵 今天你敲代码了吗
目录
网络层IP协议
网络层主要做的事情就是,路径规划以及地址管理,这就涉及IP协议的规则和特点
我们研究一下IP协议的报头
4位版本号
指的是IP协议的版本号,主要IPV4和IPV6
上述报文的结构就是 IPV4的结构
4位首部长度
这里的首部长度和 TCP 协议的一样,也是以4字节为单位的
同时由于选项的存在,IP报头的最长就是 60个字节
最短就是原本的20个字节
8位服务类型
说是8位,但是实际上只有4位有效
并且这4位彼此之间是互斥的
3位优先权字段(已经弃用)
1位保留位(必须为0)
4位TOS字段
4位TOS分别表示:最小延时.最大吐量,最高可靠性.最小成本
这四者之间互相冲突,只能选择一个
其中,最小延时实现的效果就是 传输过程中,消耗的时间最短
最大吞吐量,实现的效果就是 单位时间内,传输的数据尽可能毒多
最高可靠性,就是实现降低丢包概率
最小成本,就是实现节省系统来开销
16位总长度
指的是整个IP数据报的长度(包括报头)
那么此时如果载荷部分是 TCP数据报,那么就可以根据这个算出TCP载荷的长度了
ip数据包的总长度,减去首部长度,剩下的就是TCP数据报的长度,再减去TCP报头长度,剩下的就是TCP载荷的长度了
16位标识 3位标志 13位片偏移
那么按照我们上面所说的16位总长度,那么是不是就表明 IP数据报最长就是 64kb??
实际上,这里虽然限制了IP数据报的长度
但是,IP协议自身实现了拆包组包这样的概念
如果携带的载荷 超出了长度的限制,IP数据报就会自动拆分成多个数据报,每个数据报携带载荷的一部分
当发送到对方之后,再拼接好
假设这组数据很长,超出了64kb的上限,此时就会将上述的数据拆成多个部分,使用多个Ip数据包来进行发送
那么接收方是怎么知道.收到的这些IP数据报是怎么拼接起来的??
这三个属性即使用来实现 IP协议的拆包组包的
其中,16位标识就是用来区分,哪些数据包是需要合并的
13位片偏移就是表示,若干个要拼接的数据包的先后顺序
而3位标识,实际上只有两位有效,其中一个用来表示,该数据包是否触发了拆包的效果(是否需要组包)
另一个标志位是结束标志,表示当前这个包就是最后一个要组包的部分
上述组包的过程完全是Ip本身负责的,与载荷中保存的是什么数据,就没有任何关系了
那么既然这样的话,IP协议都能组包了,为什么UDP还有64KB的限制??
实际上,从直观上来说.把上述数据拆成多份,分成多个IP数据包发送,好像也是OK
但是拆出来的数据传输过去之后,也是要还原成原来的摸样,这里还原出来的数据还是要交给UDP使用
在UDP这一层就需要对上述数据进行解析,就会取出8个字节作为报头,剩下的就是载荷,但是载荷具体多长??
还是会尝试从报头里面读出来长度,这时候,最长还是64kb
8位生存时间
IP数据报要在网络上转发,这个属性就是用来限制一个数据在网络上转发的最大次数
一个IP数据报,初始情况下,就会有 一个TTL的值(32 / 64)
这个整数每经过一个路由器的转发,就要 -1,减到0的时候,这个数据报就要丢掉了(这个初始值实际上也是可以设置的)
的)
关键是,32 / 64这样的数值是否够用??
通常情况下是够用的
这里背后实际上涉及到一个来自于社会科学的理论 => "六度空间"理论
如果我只是一个普通人,想认识某一个人,那么我就可以发动我身边的朋友(假设一个人有150 - 200个朋友)
那么我联系我的朋友,我的朋友练习他们的朋友,那么最多经过6层朋友,就能够联系到世界上所有的人
对于路由器来说,路由器转发IP数据包的时候,每个路由器其实是不了解网络的全貌的,但是它能够知道相邻的设备有哪些(就类似于朋友)
所有,即使是经过少数的几次跳转,也是能够涵盖到大量的设备的,因此通常来说64这样的整数是够用的
限制生存时间(TTL)的主要目的是防止数据包在网络中无限循环或长时间滞留,从而避免网络中的数据包传输出现异常情况并提高网络的稳定性和效率。以下是限制生存时间的几个原因:
防止数据包循环: 如果网络中存在路由环路(即数据包在网络中无限循环),数据包就会在网络中不断地转发而无法到达目的地。通过限制生存时间,当数据包经过一定数量的路由器后,即使出现了环路,TTL字段也会减为0,数据包会被丢弃,从而避免了无限循环的问题。
防止数据包长时间滞留: 在网络中,可能会发生某些异常情况导致数据包无法正常到达目的地,比如路由器故障、网络拥堵等。如果没有TTL的限制,数据包可能会长时间滞留在网络中,占用网络资源并导致传输延迟增加。通过限制生存时间,即使数据包无法正常到达目的地,也能够在一定时间后被丢弃,释放网络资源。
网络拓扑变化 : 网络拓扑结构可能会发生变化,比如路由器之间的连接关系发生改变或者路由器故障。限制生存时间可以确保数据包不会永远地在网络中传输,从而适应网络拓扑结构的变化。
综上所述,限制生存时间有助于防止网络中的异常情况,保障数据包的正常传输,提高网络的稳定性和效率。
8位协议
这里就哈斯用来描述 载荷部分是哪种协议的数据报
是交给TCP协议还是UDP协议
16位首部校验和
为什么是首部校验和
就是只是针对IP报头进行校验
载荷部分不关心(无论是UDP协议还是TCP,都是自己有校验和的)
32位源IP地址 和 32位目的IP地址
我们之前说过,一个IP地址实际上就是一个32位的整数
为了让人更加容易的观察,通常表示为"点分十进制的形式"
那么既然是32位,就说明IP地址的数量就是 42亿九千万
原则上来说,每一台上网设备都要有唯一的IP地址,是不能重复的
但是这个数量在当前世界,是不够用的.尤其是移动设备的发展,极大的增加了上网设备的数量
那么IP地址不够用怎么办??
方案1:动态分配IP地址
即某个设备如果上网的话,才给他分配IP地址,不上网就不分配
但是实际上这样的机制,只能够做到缓解,不能解决
没法从根本上解决IP地址不够用的问题
方案2:NAT机制
首先,将IP地址分成两大类
(1)私网IP (局域网内部使用的IP)
以以下数字开头的都是 私网IP
java
10.*
172.16* ~ 172.31*
192.168.*
(2) 公网IP(广域网使用)
此时就约定好,公网IP必须是唯一的,私网IP在同一个局域网内不允许重复,但是在不同的局域网内允许重复
当前的上网设备虽然非常多,但是实际上大部分的设备都是在局域网内部上网的,此时就极大的缓解了IP地址不够用的问题
那么如果引入上面的模型,如何进行通信呢???
(1)同一个局域网内的设备之间进行通信
由于在同一个局域网内的设备IP是唯一的
因此此时这些设备之间是可以直接进行通信的
(2)广域网和广域网设备之间进行通信
本来就是要求广域网设备的IP要是唯一的
因此此时还是可以直接进行通信
(3)局域网1内的设备尝试访问局域网2之内的设备
这种情况是不允许的
(4) 广域网是设备主动访问局域网设备
这种情况也是不允许的
(5)局域网设备访问广域网设备
此时NAT机制就开始作用了
我们现在主要是 认识 ,私网IP是如何访问公网IP的
假设我们现在在家里,主动访问百度的服务器
大概的路径就是这样子
为了方便讨论,我们简化一下模型
此时我的电脑要发送一个数据报给百度的服务器,就会构造出来一个IP数据报
当此时的数据报到达运营商路由器的时候,运营商路由器实际上就是一个NAT设备,就会对中间经过的数据报进行 网络地址的转换
这种转换就是 ,当内网数据报经过外网的设备的时候,就会将IP数据报里面的源IP 换成路由器自己的IP
进行上述的转换,就是为了用自己的公网IP取代原来的私网IP
当我这个数据包到达百度服务器之后,百度服务器就会看到有一个5.6.7.8这样的设备给它发了个请求
但是百度服务器对我的电脑的真实私网Ip是一无所知的
实际上,我这个局域网中的其他电脑,也是通过运营商路由器来访问公网的,所有的这个局域网中的几千台几万台设备.都是通过同一个路由器的Ip来访问公网Ip的
这个就是我这台设备,对应的运营商路由器的公网Ip
此时百度服务器也会给我返回一个数据报
但是由于百度服务器只能看到 5.6.7.8这样的IP,那么形成的IP数据报如图所示
这个数据报就会返回给 运营商路由器
那么运营商路由器就要将数据报返回给我电脑
但是运营商路由器是怎么知道,要返回给哪个主机???
实际上,在运营商路由器内部,维护了一个"映射表"
这个映射表就会当前的这个当前来自于百度服务器的响应对应的 请求 是从哪个内网设备发过来的
就会根据这个记录的IP将IP替换为最初的IP
这种映射关系是通过"端口号"来实现的
如果在同一时刻,我这个局域网内也有别的主机访问百度,那么运营商路由器就是根据端口号来区分是哪台主机发送的请求
此时就会出现一种极端情况:
如果我这个局域网两台不同的主机,端口号恰好一样呢??
实际上也是通过端口号来区分的,即使端口号一样,到运营商路由器的时候,给这两个一样端口号的主机分配不一样的新端口号即可
那么我们再次回到我们一开始画的图
实际上,运营商路由器对应的图应该是这样的
此时,我的电脑/其他人的设备 与 运营商路由器之间的路由器设备,虽然没有公网Ip,但是也是一个NAT设备,
而运营商路由器与 中间路由器之间,又构成了局域网...相当于一个"套娃"的过程
我们当前的网络世界,就是通过动态分配 + NAT解决的IP不够用的问题
但是这样的方案给网络的复杂程度增加了不少,而且也没有从根本上解决问题
方案3:IPV6(终极方案)
就是引入了更长的字节数来表示 IP地址
IPV6拿16个字节来表示IP地址,就是128位,就是一共有 2 ^ 32 ^ 4这么多个Ip号,足以给地球上每一粒沙子都分配一个唯一的IP
但是实际上现在世界上还是以IPV4为主,这是因为IPV4和IPV6不兼容
最开始使用IPV4的时候,大家用的路由器,交换机 网卡 等各种设备,都是支持IPv4的设备
如果换成IpV6,就要换设备
但是实际上这两种的效率并不会相差很大,而换设备需要较大的成本
至于比较火的NAT,是纯软件的方案,只是需要更新一下路由器上面的程序(固件),成本非常低
IP地址的基本规则
网段划分
同一个局域网的主机,要按照一定的规则来分配IP地址
将IP地址(IPV4)分成两部分,前半部分是 网络号,后半部分是 主机号
网络号是用来标识局域网的,主机号是用来标识同一个局域网内的不同主机的
在同一个局域网内部,主机之间的IP,网络号是一样的,但是主机号不一样
但是我们不能说,网络号一样就是在同一个局域网内
因为在局域网之间,网络号是可以相同的,只是两个相邻的局域网 (比如同一个路由器的WAN口和LAN口),就不能相同
一旦相邻的局域网网络号相同了,就不能上网了
那么一个32位的IP地址,具体哪些是网络号,哪些是主机号??
此时就引入了一个新的概念:子网掩码
子网掩码也是一个32位的整数,左半部分都是1,右半部分都是0
此处的255就是1111 1111
那么此时假设我的Ip号:10.203.183.167, 前面的10.203就是网络号,183.167就是主机号
至于子网掩码,一般不需要我们设置,都是路由器插上就自动分配的
而学校 ,公司 等特殊场景,会有专门的人来配置
那么为啥说相邻的局域网网络号不能相同??
上述两个方框就是两个相邻的局域网(同一个路由器连接的)
此时网络号一旦相同,就会产生冲突
我们在前面说的搭配子网掩码的网段划分,是现在的方法
实际上在以前还流传着另一种方法,分成ABCDE 5类
但是实际上这个规则现在已经不用了
在这个体系下,不存在子网掩码,具体多少位是网络号,多少位是主机号,都是写死的,是硬性规定
这种做法就会浪费大量的IP
假设是A类的Ip,那么就说明,后面24位都是主机号,但是实际上,一个局域网里面并没有那么多主机
特殊的IP地址
3.10.2 特殊的Ip
主机号全是0(二进制)
这样的IP就表示网段,不应该分配给具体的主机,而是代表这个局域网
主机号全是1(二进制):
这样的IP代表广播Ip,往广播Ip上发送数据,就会发送给局域网中的所有设备
广播的一个应用场景就是,手机投屏,当我们点击投屏按钮的时候,就会弹出一个列表,让你选择投在哪个设备上,此时你的手机就是通过局域网广播地址,发送一个探测数据包,局域网内部支持投屏的设备就会给出相应,告知一些相关信息
实际上,TCP是不支持广播的,只有UDP才支持广播
这是因为TCP是有连接的 此时你按照广播地址来尝试建立连接,就代表每个设备都要进行3次握手??这是很不科学的
127.* 环回Ip(loopback)
往这个Ip中发送数据,就是自己来接收
此时即使你的电脑没联网,也是可以使用的
路由选择
所谓路由选择,就是"找路"
我们常见的高德地图,是立足于全局的数据,给你得到一个最优解
最优解不是说只有一种,而是按照不同的角度,得到最优解
比如路线最短,时间最短,少换乘,只坐地铁
但是在网络里面,路由器的寻找,则无法做到"最优解",只能做到"较优解"
因为每一台路由器无法知道整个网络的"全貌",但是可以知道它附近的网络设备情况是什么样的
对于路由器来说,在进行数据转发的时候,是无法一下就知道,目的Ip所对应的设备该如何到达,只能通过"启发式":探索性的方式,逐渐找到最终的目标
实际上,在路由器里面,维护了一个数据结构,这个数据结构记录了路由器周围的"朋友"是什么样的
当路由器收到数据的时候,就会根据目的Ip查询路由表,.看看这个Ip在路由表是否存在
如果存在,那就直接按照目标的位置进行转发即可
如果不存在,就会在"朋友"里面找到一个"最神通广大"的,把这个数据交给这个"朋友",让它想办法
至于这个"神通广大",指的就是路由器的下一跳表项,就牵扯到"路由器生成算法"
比较简单的情况就是,家里的路由器的下一跳表项就是 wan口连接的运营商的路由器
感谢您的访问!!期待您的关注!!!
T04BF
🫵 今天记得敲代码