「前言」文章内容是网络层的IP协议讲解。
「归属专栏」网络编程
「主页链接」个人主页
「笔者」枫叶先生(fy)
IP指网际互连协议,
Internet Protocol
的缩写,是TCP/IP体系中的网络层协议。
网络层解决的问题
网络层要解决的问题就是:将数据从一台主机跨网络送到另一台主机,也就是数据的路由(路径选择)
基本概念
路径选择
数据进行的网络传输一般都是跨网络的,而路由器就是连接多个网络的硬件设备,因此数据在进行跨网络传输时一定需要经过一个或多个路由器
version
):指定IP协议的版本,对于IPv4来说,就是4header length
):表示IP报头的长度,以4字节为单位(IP头部最大长度是60字节,基础报头长度为20字节)Type Of Service
):3位优先权字段(已经弃用),4位TOS字段,和1位保留字段(必须置为0)。4位TOS分别表示:最小延时,最大吞吐量,最高可靠性,最小成本。这四者相互冲突,只能选择一个。比如对于ssh/telnet这样的应用程序,最小延时比较重要,而对于ftp这样的程序,最大吞吐量比较重要。total length
):IP报文(IP报头+有效载荷)的总长度,用于将各个IP报文进行分离id
):唯一的标识主机发送的报文,如果数据在IP层进行了分片,那么每一个分片对应的id都是相同的MTU
,IP协议就会丢弃该报文。第三位表示“更多分片”,如果报文没有进行分片,则该字段设置为0,如果报文进行了分片,则除了最后一个分片报文设置为0以外,其余分片报文均设置为1(最后一个分片报文该字段为0,类似于结束标志,类似于C语言的字符串以'\0'
结尾)framegament offset
):分片相对于原始数据开始处的偏移,表示当前分片在原数据中的偏移位置,实际偏移的字节数是这个值× 8
得到的。因此除了最后一个报文之外,其他报文的长度必须是8的整数倍,否则报文就不连续了Time To Live,TTL
):数据报到达目的地的最大报文跳数,一般是64,每经过一个路由,TTL -= 1
,一直减到0还没到达,那么就丢弃了,这个字段主要是用来防止出现路由循环Source IP Address
):指示发送该数据报的源主机的IP地址。Destination IP Address
):指示接收该数据报的目标主机的IP地址如何进行报头与有效载荷的分离??即如何解包
IP协议的报头与TCP协议的报头类似,当IP从底层获取到一个报文后,虽然IP不知道报头的具体长度,但IP报文的前20个字节是IP的基本报头,并且这20字节当中涵盖4位首部长度
IP解包的过程如下:
0000 ~ 1111
,即最大长度是15,又因为4位首部长度的基本单位是4字节,所以15*4=60
字节[20 ~ 60]
注:不同的协议层对数据包有不同的称谓,在传输层叫做数据段(segment
),在网络层叫做数据报 (datagram
),在链路层叫做数据帧(frame
)
IP如何决定将有效载荷交付给上层的哪一个协议?即如何分用
如何解包与分用已经解决,封装就是逆过来
8位生存时间
32位源IP地址和32位目的IP地址
16位标识(id)、3位标志字段、13位片偏移最后再谈
IP地址的构成
IP地址由网络号和主机号两部分构成:
网络号:保证相互连接的两个网段具有不同的标识
主机号:同一网段内,主机之间具有相同的网络号,但是不同的主机必须有不同的主机号
P协议有两个版本,IPv4和IPv6。后序凡是提到IP协议,没有特殊说明的,默认都是指IPv4(IPv4与IPv6不兼容)
/
,并在/
后面加上一个数字
,这就表示从头数到第几位为止属于网络标识(网络号)例如,下图中路由器连接了两个网段(子网):
为什么要进行IP网段划分??(为什么要进行子网划分?)
举个例子:
0030115
,张三不认识这个学号,于是张三就一直问走过来的同学:你的学号是多少…0030115
学号的学院管理者,再由该学院的管理者交给学号为0030115
的同学。这不就大大提高了查找的效率吗因此,为了提高数据路由查找效率,对IP地址进行了IP网段划分(子网划分)
DHCP
通过合理设置主机号和网络号,就可以保证在相互连接的网络中,每台主机的IP地址都不相同
Dynamic Host Configuration Protocol
,动态主机配置协议)是一个局域网的网络协议,使用UDP协议工作,主要有两个用途:给内部网络或网络服务供应商自动分配IP地址,给用户或者内部网络管理员作为对所有计算机作中央管理的手段当你的设备连接WiFi成功,路由器会自动分配一个IP给你的设备,然后你的设备就有了IP地址,就可以进行上网了(没有联网的设备没有IP地址)
是谁进行子网划分??
如何进行网段划分??(如何进行子网划分)
过去曾经提出一种划分网络号和主机号的方案,就是把所有IP地址分为五类
0.0.0.0
到127.255.255.255
128.0.0.0
到191.255.255.255
192.0.0.0
到223.255.255.255
224.0.0.0
到239.255.255.255
240.0.0.0
到247.255.255.255
判断一个IP地址属于哪一类网络,可以通过查看IP地址的第一个字节来确定(前8个比特位)
CIDR(无类别域间路由,Classless Interdomain Routing)
但随着网络的飞速发展,这种划分方案的局限性很快就显现出来了
为了避免这种情况,于是又提出了新的划分方案,称为CIDR(Classless Interdomain Routing
),CIDR是一种IP地址分配和路由的策略,旨在更有效地利用IPv4地址
subnet mask
)的概念按位与
”操作,就能够得到当前所在网络的网络号此时一个网络就被更细粒度的划分成了一个个更小的子网,通过不断的子网划分,子网中IP地址对应的主机号就越来越短,因此子网当中可用IP地址的个数也就越来越少,这也就避免了IP地址被大量浪费的情况
子网划分的例子如下:
需要注意的是,子网划分不是只能进行一次,可以在划分出来的子网的基础上继续进行子网划分
并不是所有的IP地址都能够作为主机的IP地址,有些IP地址本身就是具有特殊用途的。
140.252.40.0
或140.252.40.64
,这个地址代表网络号,不能分配给主机140.252.40.255
或140.252.40.79
,这个地址代表广播地址,也是不能分配给主机127.*
的IP地址用于本机环回(loop back
)测试,通常是127.0.0.1
广播地址
本地环回
IP地址(IPv4)是一个4字节32位的正整数,因此一共有2^32
个IP地址,也就是将近43亿个IP地址。但TCP/IP协议规定,每个主机都需要有一个IP地址
所以43亿个IP地址其实早就不够用了,因此才提出了CIDR的方案对已经划分好的五类网络继续进行子网划分,其目的就是为了减少IP地址的浪费,根本原因就是IP地址本来就不够了,所以不能够再浪费了。
CIDR虽然在一定程度上缓解了IP地址不够用的问题,因为CIDR提高了IP地址的利用率,减少了浪费,但IP地址的绝对上限并没有增加,依旧是43亿左右
解决IP地址的三种方法
IPv6我国目前搞得比较好,但是由于与IPv4不兼容,导致推广迟迟无法展开。因为IPv4是内嵌在OS里面的,还有底层设施与IPv6不兼容,导致IPv6的推广很困难
由于NAT技术的出现,IP地址不足的问题得到了解决,但是IP地址的绝对上限并没有增加(NAT技术依旧没有彻底解决这个问题)
NAT技术的出现,虽然阻碍了IPv6的发展,但是也帮助了我国IPv6的推广,通过NAT技术,可以把IPv6的地址转化成IPv4的地址,目前我国大部分互联网公司的内网环境都是IPv6
美国虽然也搞IPv6,但是没有动力(我闲着没事干为什么要推翻我的IPv4)
彻底解决IP地址不足的问题还是得靠IPv6
如果一个组织内部组建局域网,IP地址只用于局域网内的通信,而不直接连到Internet上,理论上使用任意的IP地址都可以,但是RFC 1918规定了用于组建局域网的私有IP地址:
10.
,前8位是网络号,共16,777,216个地址172.16.
到172.31.
,前12位是网络号,共1,048,576个地址192.168.
,前16位是网络号,共65,536个地址查看自己主机的IP
ifconfig
:该命令的作用是显示和配置网络接口的信息
比如,购买的Linux服务器,输入该命令
eth0
代表的是:通常表示系统的第一个以太网接口。它是物理网络接口,用于连接到局域网或互联网。eth0可以是有线或无线以太网接口,具体取决于你的系统设置和网络硬件lo
是本地回环接口(loopback interface
),也被称为环回地址。它是一个虚拟网络接口,用于系统内部通信。lo接口的IP地址通常是127.0.0.1
,子网掩码为255.0.0.0
。它允许系统内部的进程和服务之间进行通信,而不需要通过物理网络接口eth0
接口中的inet
对应的地址192.168.0.213
,就是私网IP
用于连接Linux服务器的IP叫做公网IP
注:在Windows下查看使用命令ipconfig
我们为什么要给运营商交钱??
我们享受的是互联网公司提供服务,比如刷抖音,在淘宝上买东西…,但是我们并没有给互联网公司交钱(上网的费用),而是把钱交给了运营商,为什么把钱交给运营商而不是互联网公司,我们明明享受的是互联网公司提供的各种服务??
比如你的手机号欠费了,你还想进行上网,在经过运行商的时候,运营商就会对你的账号进行认证,发现你欠费了,直接丢掉了你的请求,不转发给相应的服务器
也就是说,用户上网的数据首先必须经过运营商的相关网络设备,然后才能发送到互联网公司对应的服务器,所以我们想上网必须要给运营商交钱
路由器的功能
路由器又分家用版路由器和企业级路由器:
192.168.
的10.
或者是172.16.
到172.31.
数据是如何发送到对应的服务器上的
路由器是连接两个或多个子网的硬件设备,在路由器上有两种网络接口,分别是LAN口
和WAN口
:
LAN口(Local Area Network)
:表示连接本地网络的端口,主要与家庭网络中的交换机、集线器或PC相连 WAN口(Wide Area Network)
:表可以理解为连接公网网络的接口,一般指互联网我们将LAN口的IP地址叫做LAN口IP(对内),也叫做子网IP,将WAN口的IP地址叫做WAN口IPO,也叫做外网IP(对外)
我们使用的电脑、家用路由器、运营商路由器、广域网以及我们要访问的服务器之间的关系大致如下:
192.168.1.1
),子网内的主机IP地址不能重复,但是子网之间的IP地址就可以重复了注:私网IP不能出现在公网当中
为什么私网IP不能出现在公网当中?
由于私网IP不能出现在公网当中:
源IP地址
替换成路由器的WAN口IP
,这样逐级替换,最终数据包中的源IP地址成为一个公网IP,这种技术成为NAT
(Network Address Translation
,网络地址转换,把私有地址转换成合法的IP地址)数据转发的大致流程如下:
122.77.241.3/24
源IP
替换成路由器的WAN口IP
,再转发给跟自己直接相连的另一个子网源IP
替换成路由器的WAN口IP
,然后直接把数据包转发到公网上数据包路由的过程(类似于问路的过程,一个个接力下去)
源MAC地址
到目的MAC地址
之间的帧传输区间
IP数据包的传输过程也和问路一样,IP数据包的传输过程中会遇到很多路由器
这些路由器会帮助数据包进行路由转发,每当数据包遇到一个路由器后,对应路由器都会查看该数据的目的IP地址,并告知该数据下一跳应该往哪跳
如何判定当前这个数据包该发送到哪里?
IP数据包中的
目的IP
,在路由器的路由表查找结果可能有以下三种:
查看路由表
路由表可以使用route
命令查看,该命令可以显示当前系统的路由表
条目部分解释:
Destination
:目标网络或主机的IP地址Gateway
:下一跳网关的IP地址,即发送数据包到目标网络或主机的下一跳路由器Genmask
:目标网络或主机的网络掩码Flags
:标志位,用于表示路由表项的状态和属性。常见的标志位包括U(路由表项是可用的),G(路由表项是由网关指定的,表示此条目的下一跳地址是某个路由器的地址),H(路由表项是一个主机路由)Iface
:接口,表示数据包将通过哪个网络接口发送其中一些字段的意思:
default
:表示这是默认路由(网关),即当系统找不到匹配的目标网络或主机时,将使用这个路由表项0.0.0.0
:表示目标网络或主机为任意网络或主机UG
:表示这是一个默认路由表项,并且网关字段是有效的,没有G标志的条目表示目的网络地址是与本机接口直接相连的网络,不必经路由器转发查路由表的过程
当IP数据包到达路由器时,路由器就会查该数据包的目的IP地址,依次与路由表中的子网掩码
Genmask
进行“按位与”操作(遍历路由表),然后将结果与子网掩码对应的目的网络地址Destination
进行比对,如果匹配则说明该数据包下一跳就应该跳去这个子网,此时就会将该数据包通过对应的发送接口Iface
发出
如果将该数据包的目的IP地址与子网掩码进行“按位与”后,没有找到匹配的目的网络地址,此时路由器就会将这个数据包发送到默认路由,也就是路由表中目标网络地址中的default
。可以看到默认路由对应的Flags
是UG
,实际就是将该数据转给了另一台路由器,让该数据在另一台路由器继续进行路由
数据包不断经过路由器路由后,最终就能到达目标主机所在的目标网络,此时就不再根据该数据包目的IP地址当中的网络号进行路由了,而是根据目的IP地址当中的主机号进行路由,最终根据该数据包对应的主机号就能将数据发送给目标主机
路由表可以由网络管理员手动维护(静态路由),也可以通过一些算法自动生成(动态路由)
路由表生成算法:距离向量算法, LS算法, Dijkstra算法等
注意:>网络层的IP协议是为数据的路由提供决策,而真正的对数据进行转发路由的是数据链路层(正真做事的)
最后补充上面没有谈到的16位标识(id)、3位标志字段、13位片偏移
下面进行解释16位标识(id)、3位标志字段、13位片偏移
这里会涉及到数据链路层的问题
最大传输单元 MTU
Maximum Transmission Unit,MTU
)是指在网络通信中,数据链路层能够传输的最大数据帧的大小。MTU的大小通常由网络设备或网络协议规定,它限制了一次可传输的数据量IP报头+有效载荷 <= 1500字节
既然有分片,就也要有组装,分片与组装是在IP层完成的,分片与组装单纯是IP协议的行为,与上一层传输层和下一层数据链路层没有任何关系
注意:IP的分片与组装不是主流情况,IP的分片与组装是特殊情况,主流的情况下一篇文章数据链路层再谈
如何分片和组装??
靠这三个字段即可完成分片与组装:
id
):唯一的标识主机发送的报文,如果数据在IP层进行了分片,那么每一个分片对应的id都是相同的MTU
,IP协议就会丢弃该报文。第三位表示“更多分片”,如果报文没有进行分片,则该字段设置为0,如果报文进行了分片,则除了最后一个分片报文设置为0以外,其余分片报文均设置为1(最后一个分片报文该字段为0,类似于结束标志,类似于C语言的字符串以'\0'
结尾)framegament offset
):分片相对于原始数据开始处的偏移,表示当前分片在原数据中的偏移位置,实际偏移的字节数是这个值× 8
得到的。因此除了最后一个报文之外,其他报文的长度必须是8的整数倍,否则报文就不连续了注意:被分片的报文都要重新封装IP报头
怎么知道一个IP报文是否被分片了?
同一个报文的分片如何都能被识别出来?
如何判断分片的报文哪一个是第一个,哪一个是最后一个?
多分片标志位为0 && 片偏移>0
即代表最后一个分片报文多分片标志位为1 && 片偏移 == 0
进行判断,如果满足则是第一个分片报文如何得知被分片的报文有没有被收全?如何进行组装,哪个分片报文在前,哪个平分报文在后?
如何保证组装起来的报文是正确的?
数据的分片和组装都是由IP层完成的
分片好不好?
答案是,肯定是不好,虽然传输层并不关心IP层的分片问题,但分片对传输层也是有影响
99.99%
,一个报文在IP层发生了分片,分成了三个分片报文,此时该报文丢包概率就会增加,99.99%*99.99%*99.99% < 99.99%
如何减少分片?
实际数据分片的根本原因在于传输层一次向下交付的数据太多了,导致IP无法直接将数据向下交给MAC帧,如果传输层控制好一次交给IP的数据量不要太大,那么数据在IP层自然也就不需要进行分片。
MSS = MTU - 20 - 20
,所以MSS的值一般为1460字节总结来说,实际数据分片的原因是传输层一次向下交付的数据太多了,为了避免数据分片,需要控制TCP发送的数据大小在MSS以内
分片的过程
假设IP层要发送3000字节的数据(IP报头+有效载荷),由于该数据超过了MAC帧规定的MTU(1500),因此IP需要先将该数据进行分片,然后再将一个个的分片交给MAC帧进行发送
假设IP层添加的IP报头的长度就是20字节,并按下列方式将数据分片后形成了三个分片报文:
分片报文 | 报文字节总数 | IP报头字节数 | 有效载荷 | 16位标识 | 更多分片标志位 | 13位片偏移 |
---|---|---|---|---|---|---|
1 | 1500 | 20 | 1480 | 假设是111 | 1 | 0 |
2 | 1500 | 20 | 1480 | 111 | 1 | 185 |
3 | 60 | 20 | 40 | 111 | 1 | 370 |
注意:13位片偏移当中记录的字节数是当前分片在原数据开始处的偏移字节数的值÷ 8
得到的
关于组装的问题上面已经谈论了大部分,不再赘述,下一篇进入数据链路层的MAC帧协议
「 作者 」 枫叶先生
「 更新 」 2023.10.14
「 声明 」 余之才疏学浅,故所撰文疏漏难免,
或有谬误或不准确之处,敬请读者批评指正。