【网络编程】网络层协议——IP协议

一、TCP与IP的关系

IP层的核心作用是定位主机,具有将一个数据从主机A发送到主机B的能力,但是又能力又不能保证一定能够送到,所以这时就需要TCP起作用了,TCP可以通过超时重传、拥塞控制等策略来保证数据能够发送到B主机。
所以TCP提供的是策略(保证可靠),而IP付出的是行动。

二、IP协议基本概念

网络层要解决的问题就是,将数据从一台主机送到另一台主机,也就是数据的路由

  • 路径选择

在路径选择中,目的IP非常重要,决定了路径该如何走。
数据进行的网络传输一般都是跨网络的,而路由器就是连接多个网络的硬件设备,因此数据在进行跨网络传输时一定需要经过多个路由器。
ip = 目标网络 + 目标主机

举个例子,我们要到北京故宫,北京就像目标网络,故宫就像目标主机。

所以我们要先找到目标网络再找到目标主机。
IP地址是进行路由的根本。

三、IP协议格式

在这里插入图片描述

  • 4位版本号:指定IP协议的版本(IPv4/IPv6),对于IPv4来说,就是4。
  • 4位首部长度:表示IP报头的长度,以4字节为单位。
  • 8位服务类型:找到最优路径。
  • 16位总长度:IP报文(IP报头+有效载荷)的总长度,用于将各个IP报文进行分离。
  • 16位标识:唯一的标识主机发送的报文,如果数据在IP层进行了分片,那么每一个分片对应的id都是相同的。
  • 3位标志字段:第一位保留,表示暂时没有规定该字段的意义。第二位表示禁止分片,表示如果报文长度超过MTU,IP模块就会丢弃该报文。第三位表示“更多分片”,如果报文没有进行分片,则该字段设置为0,如果报文进行了分片,则除了最后一个分片报文设置为0以外,其余分片报文均设置为1。
  • 13位片偏移:分片相对于原始数据开始处的偏移,表示当前分片在原数据中的偏移位置,实际偏移的字节数是这个值× 8得到的。因此除了最后一个报文之外,其他报文的长度必须是8的整数倍,否则报文就不连续了。
  • 8位生存时间:数据报到达目的地的最大报文跳数,一般是64,每经过一个路由,TTL -= 1,一直减到0还没到达,那么就丢弃了,这个字段主要是用来防止出现路由循环。
  • 8位协议:表示上层协议的类型。
  • 16位首部检验和:使用CRC进行校验,来鉴别数据报的首部是否损坏,但不检验数据部分。
  • 32位源IP地址和32位目的IP地址:表示发送端和接收端所对应的IP地址。
  • 选项字段:不定长,最多40字节。

3.1 IP如何将报头与有效载荷进行分离&向上交付?

  • 报头与有效载荷分离

首先要知道报文部分把选项除去一共是20字节(跟TCP一样)
IP报头中有一个是4位首部长度,基本单位是四字节。
所以大小范围是【0 ~ 60】字节。根据计算,如果没有选项,那么就填写0101(5的二进制)。

既然报头和选项都能读取到了,总长度也知道了(16位总长度),那么剩下的就是有效载荷了。


  • 向上交付给哪个协议?

在IP报头当中有一个字段叫做8位协议,该字段表示的就是上层协议的类型,IP就是根据该字段判定应该将分离出来的有效载荷交付给上层的哪一个协议的。该字段是发送方的IP层从上层传输层获取到数据后填充的,比如是上层TCP交给IP层的数据,那么该数据在封装IP报头时的8位协议填充的就是TCP对应的编号。

扫描二维码关注公众号,回复: 16004786 查看本文章

3.2 8位生存时间

报文在网络传输过程中,可能因为某些原因导致报文无法到达目标主机,比如报文在路由时出现了环路路由的情况,或者目标主机已经异常离线了,此时这个报文就成了一个废弃的游离报文。

为了避免网络当中出现大量的游离报文,于是在IP的报头当中就出现了一个字段,叫做8位生存时间)。8位生存时间代表的是报文到达目的地的最大报文跳数,每当报文经过一次路由,这里的生存时间就会减一,当生存时间减为0时该报文就会被自动丢弃,此时这个报文就会在网络中消散。

3.3 32位源IP地址和32位目的IP地址

我们知道数据想要发送到对端主机,要在路由器之间一跳一跳的过去。而路由器的转发就需要源IP和目的IP。
当接收端收到了发送端发来的数据后,接收端可能也想要给发送端发送数据,因此发送端在发送数据时除了需要指明该数据的目的IP地址,还需要指明该数据的源IP地址,也就是发送端的IP地址。即便接收端收到数据后没有数据想要发送给发送端,但至少接收端需要向发送端发送一个响应报文,表明发送端发送的数据已经被接收端可靠的收到了,因此发送出去的数据除了需要指明该数据的目的IP地址,还需要指明该数据的源IP地址。

  • 绑定socket

端口号的绑定其实是TCP/UDP层用来进行从操作系统向进程交付数据。
IP地址就是绑定在IP层,用于数据在网络传输过程中的路由转发。

发送数据时我们不需要指明发送数据的源IP地址和源端口号,因为传输层和网络层都是在操作系统内核当中实现的,数据在进行封装时操作系统会自行填充上对应的源IP地址和源端口号。

四、网段划分

4.1 为什么子网划分?

先讲一个场景:

我们入学的学号不是随便乱给的,包含了入学年份、学院、班级等信息,我们假设学号只包含学院号 + 自己的编号。那么我们通过学号就能知道你是哪个学院的,是谁。
假设每个学院都有个负责人,他自己也有个学号,每个学院的负责人都在一个大群里。
现在有个学生(张三)的学生证丢了, 当被人(李四)捡到了后,李四发现不是自己学院的人,但不知道张三到底是哪个学院的,然后李四就只能把这个学生证给学院的负责人(王五),王五是知道学院的编号的,他就可以把学生证交给对应学院的负责人(赵六),然后赵六就可以把学生证归还给张三了。

我们把张三和李四叫做源主机和目标主机,负责人们就是路由器,院里的群我们叫做局域网,把负责人的群叫做公网

每个同学都以一个学号(IP地址),而且每个同学都得归类到每个学院。
类比到计算机就是:
互联网中每个主机都隶属于一个子网, 以方便定位到具体主机。

4.2 IP地址的划分

IP地址由网络号和主机号两部分构成:

网络号:保证相互连接的两个网段具有不同的标识。
主机号:同一网段内,主机之间具有相同的网络号,但是必须有不同的主机号。

在这里插入图片描述
路由器连接了两个网段,一般主机标识都是1。对于网络标识来讲,同一网段内主机的网络标识是相同的,不同网段内主机的网络标识是不同的。而对于主机标识来讲,同一网段内主机的主机标识是不同的,不同网段内主机的主机标识是可以相同的。

  • 不同的子网其实就是把网络号相同的主机放到一起。
  • 如果在子网中新增一台主机,则这台主机的网络号和这个子网的网络号一致,但是主机号必须不能和子网中的其他主机重复。

我们可以看到一个子网内有很多主机,这些主机是由路由器管理的。实际手动管理IP地址是一个非常麻烦的事情,当子网中新增主机时需要给其分配一个IP地址,当子网当中有主机断开网络时又需要将其IP地址进行回收,便于分配给后续新增的主机使用。

  • DHCP技术

因此对于IP地址的分配和回收一般不会手动进行,而是采用DHCP技术。
DHCP通常被应用在大型的局域网环境中,其主要作用就是集中地址管理、分配IP地址,使网络环境中的主机动态获得IP地址、Gateway地址、DNS服务器地址等信息,并能够提升地址的使用率。
DHCP是一个基于UDP的应用层协议,一般的路由器都带有DHCP功能,因此路由器也可以看作一个DHCP服务器。

当我们连接WiFi时,本质就是路由器就会给你动态分配了一个IP地址,然后你就可以基于这个IP地址进行各种上网动作了。

4.3 分类划分法

过去曾经提出一种划分网络号和主机号的方案,就是把所有IP地址分为五类,如下图所示:
在这里插入图片描述
当要判断一个IP地址是属于哪一类时,只需要遍历IP地址的前五个比特位,第几个比特位最先出现0值,那么这个IP地址对应就属于A、B、C、D、E类地址。

这里就是把IP地址看成一个大蛋糕,按照ABCDE分成若干块,要多少A类或者B类自己去申请即可。这种划分方法就叫做分类划分法

但是可以发现一些缺陷,比方说一个学校申请了一个B类,B类地址的主机号占16个比特位,因此理论上一个B类网络当中允许有65536台主机。但是一般用不到这么对,就会导致资源的浪费

为了解决这种问题,在分类划分法的基础上出现了一种解决方案:

  • CIDR

引入一个额外的子网掩码来区分网络号和主机号
子网掩码也是一个32位的正整数,通常用一串 “0” 来结尾
将IP地址和子网掩码进行 按位与 操作, 得到的结果就是网络号
网络号和主机号的划分与这个IP地址是A类、B类还是C类无关

目标网络和子网掩码是路由器内置好的。

此时一个网络就被更细粒度的划分成了一个个更小的子网,通过不断的子网划分,子网中IP地址对应的主机号就越来越短,因此子网当中可用IP地址的个数也就越来越少,这也就避免了IP地址被大量浪费的情况。

举个例子:

比如在某一子网中将IP地址的前24位作为网络号,那么该网络对应的子网掩码的32个比特位中的前24位就为1,剩下的8个比特位为0,将其用点分十机制表示就是255.255.255.0。
假设该子网当中有一台主机对应的IP地址是140.252.20.68,那么将这个IP地址与该网络对应的子网掩码进行“按位与”操作后得到的就是140.252.20.0,这就是这个子网对应的网络号。
实际在用子网掩码与子网当中主机的IP地址进行“按位与”操作时,本质就是保留了主机IP地址中前24个比特位的原貌,将剩下的8个比特位的值清0了而已,也就是将主机号清0了,那么子网地址范围就为:【140.252.20.0 ~ 140.252.20.255】

4.4 特殊的IP地址

不是所有的IP都会在公网中使用,有些IP地址是有特殊的作用的:

  • 将IP地址中的主机地址全部设为0,就成为了网络号,代表这个局域网。
  • 将IP地址中的主机地址全部设为1,就成为了广播地址,用于给同一个链路中相互连接的所有主机发送数据包。
  • 127.*的IP地址用于本机环回测试,通常是127.0.0.1。

4.5 IP地址的数量限制

IPV4是一个三十二位的正整数,所以有2^32个IP地址,相当于43亿个,每一台主机都需要有一个IP,而且现在每个人都有手机,可以发现IP地址是明显不足的

上面的CIDR方案只是提高了利用率,但是绝对上限并没有变化。

  • 解决IP地址不足问题

有三种方式:

动态分配IP地址:只给接入网络的设备分配IP地址,因此同一个MAC地址的设备,每次接入互联网中,得到的IP地址不一定是相同的。
NAT技术:能够让不同局域网当中同时存在两个相同的IP地址(私有IP和公网IP做转换),NAT技术不仅能解决IP地址不足的问题,而且还能够有效地避免来自网络外部的攻击,隐藏并保护网络内部的计算机。
IPv6:IPv6用16字节128位来表示一个IP地址,能够大大缓解IP地址不足的问题。但IPv6并不是IPv4的简单升级版,它们是互不相干的两个协议,彼此并不兼容,因此目前IPv6还没有普及。

4.6 私有IP地址与共网IP地址

如果一个组织内部组建局域网,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,其余的则称为公网IP(或全局IP)。

因为私有IP只能在局域网内出现,所以不同的子网内可能有相同的私有IP,这样就解决了IP不足的问题

我们可以通过ifconfig命令来查看我们这台机器的私网IP:
在这里插入图片描述
可以看到这个IP正好在第二种私网IP范围内。

4.7 LAN口IP与WAN口IP

路由器是可以构建局域网的,而且一定是横跨两个子网。
所以路由器至少会配置两个IP,分别是LAN口和WAN口:

  • LAN口:表示连接本地网络的端口,主要与家庭网络中的交换机、集线器或PC相连。
  • WAN口:表示连接广域网的端口,一般指互联网。

LAN口IP对内,WAN口IP对外
在这里插入图片描述

① 从运营商机房拉出的网线插在了家用路由器的WAN口上。
② 个人设备是插在家用路由器的LAN口上。
在这里插入图片描述

可以看到这两个运营商路由器现在属于一个子网中,怎么让他们划分到不同的子网呢?

通过更改子网掩码即可

4.8 数据包的转发流程(NAT技术)

在这里插入图片描述

由上图可知数据刚出来的时候并不是直接到公网上,而是先交给家用路由器,再交给运营商路由器做内网转发,转发到一定程度后再转发到公网,最后由公网到达目标服务器。

现在假设我们要从我们自己的主机访问目标主机:
在这里插入图片描述

首先我们自己的主机判断了目标IP并不在不在当前局域网,所以会把数据包直接转给家用路由器,家用路由器也发现目标IP并不在不在当前局域网,所以就交给运营商路由器,运营商路由器直接连在公网,IP是唯一确认的,所以就找到了目标服务器,把数据包交给目标服务器即可。

但是这样就会出现两个问题:
1️⃣ 私有IP不能出现在公网上,目标服务器收到的src就是个私有IP。
2️⃣ 因为私有IP在不同的子网里都有,那么响应交给谁呢?

所以真实的转发场景如下:
当数据包到达家用路由器的时候,路由器会把源IP替换成WAN口IP
在这里插入图片描述

对外路由器(运营商路由器)收到报文后,也会重复上面的操作:
在这里插入图片描述
然后就可以把这个替换过的报文转发给目标服务器。
此时往回响应的时候src就是运营商路由器,这样就是到返回到哪个子网了,至于后续怎么响应回自己的主机在后面数据链路层协议讲。
这种在转发报文的时候不断的把源IP和WAN口IP进行替换的技术就叫做NAT(网络地址转换)

五、路由

5.1 数据路由过程

路由用一句话来说就是:在复杂的网络结构中找出一跳通往终点的路。

举个现实生活中的例子:

假设在信息不发达的年代,我们到了一个陌生的地方,我们只知道目的地的名字,怎么到这个地方呢?
最好的方法就是问人,那么这个人要么自己不知道但可以告诉你该问谁,要么知道具体位置,要么他站的地方就是目的地,不用找了。

我们自己就是数据包,目的地就是目标IP,问的路人就是路由器,而路人思考的过程就是查路由表,这整个过程就是路由的过程

IP数据包的传输过程中会遇到很多路由器,这些路由器会帮助数据包进行路由转发,每当数据包遇到一个路由器后,对应路由器都会查看该数据的目的IP地址,并告知该数据下一跳应该往哪跳。

路由器的查找结果可能有以下三种:

  • 路由器经过路由表查询后,得知该数据下一跳应该跳到哪一个子网。
  • 路由器经过路由表查询后,没有发现匹配的子网,此时路由器会将该数据转发给默认路由。
  • 路由器经过路由表查询后,得知该数据的目标网络就是当前所在的网络,此时路由器就会将该数据转给当前网络中对应的主机。

5.2 路由表

每个路由器内部会维护一个路由表,在Windows下可以用route PRINT命令查看路由表
在这里插入图片描述
在Linux下我们可以通过route命令查看云服务器上对应的路由表。
在这里插入图片描述

  • Destination:代表的是目的网络地址。

  • Gateway:代表的是下一跳地址。

  • Genmask:代表的是子网掩码。

  • Flags:U表示正在使用,G就表示默认网关(路由器)。

  • Iface:代表的是发送接口。

  • 查询路由表过程

当IP数据包到达路由器时,遍历路由表的每一个条目,拿着目的IP依次与路由表中的子网掩码 Genmask进行“按位与”操作,来确定该报文要去的目标网络,对比运算结果与目标网络Destination,如果一样,将该数据包通过对应的发送接口Iface发出。
如果都没有匹配上目标网络Destination,此时路由器就会将这个数据包发送到默认路由,也就是路由表中目标网络地址中的default

总结:
1️⃣ 遍历路由表。
2️⃣ 目的IP & 子网掩码,找到要去的目标网络,没找到就走默认网关。
3️⃣ 通过Iface发送。

六、分片与组装

在路由器之间传递的确实是IP报文,但真正在网线上跑的是MAC帧。
Mac帧是数据链路层的协议。

  • 最大传输单元

MAC帧作为数据链路层的协议,它会将IP传下来的数据封装成数据帧,然后发送到网络当中。但MAC帧携带的有效载荷的最大长度是有限制的,也就是说IP交给MAC帧的报文不能超过某个值,这个值就叫做最大传输单元(MTU, 可修改),这个值的大小一般是1500字节。

但是IP也不能决定单个报文的大小,在网络中决定报文大小的是TCP。
所以IP层自己想了个办法:

如果IP层要传送的数据超过了1500字节,那么就需要先在IP层对该数据进行分片,然后再将分片后的数据交给下层MAC帧进行发送。

发送方的IP层负责分片,接收方的IP层负责封装。

而分片是通过IP协议报头的这三个字段完成的:
在这里插入图片描述

  • 16位标识:唯一的标识主机发送的报文,如果数据在IP层进行了分片,那么每一个分片对应的id都是相同的
  • 3位标志字段第一位保留,表示暂时没有规定该字段的意义。第二位表示禁止分片,表示如果报文长度超过MTU,IP模块就会丢弃该报文。第三位表示“更多分片”,如果报文没有进行分片,则该字段设置为0,如果报文进行了分片,则除了最后一个分片报文设置为0以外,其余分片报文均设置为1。
  • 13位片偏移分片相对于原始数据开始处的偏移,表示当前分片在原数据中的偏移位置,实际偏移的字节数是这个值× 8得到的。因此除了最后一个报文之外,其他报文的长度必须是8的整数倍,否则报文就不连续了。

6.1 切片流程

假设IP层要发送3000字节大小的数据,假设IP报头不含选项字段,那么加上报头就是3020字节。超过了最大传输单元,需要切分。
这里要注意我们每个切分下来的都是纯数据,每部分数据都要添加报头

首先可以先切下1500字节(含原始的报头),然后还剩1520的纯数据,再切下1480的纯数据,加上20字节的报头,刚好构成1500字节,还剩下40字节的纯数据,把这40个字节纯数据也加上报头,就是60字节。

最终就分成了三部分:1500,1500,60

接下来就填写三个报头的三个字段。

分片报文序号 16位标识 更多分片 13位片偏移
1 1111 1 0
2 1111 1 1500
3 1111 0 2980

6.2 组装流程

通过16位标识来确定这些报文曾经属于一个报文,通过更多分片加上13位片偏移来确定该报文有没有被切分以及首尾以及顺序。

先找到分片报文中13位片偏移为0的分片报文,然后提取出其IP报头当中的16位总长度字段,通过计算即可得出下一个分片报文所对应的13位片偏移,按照此方式依次将各个分片报文拼接起来。
直到拼接到一个“更多分片”标志位为0的分片报文,此时表明分片报文组装完毕。

6.3 切片的影响

首先要知道,尽量不建议切片
因为一个报文被切成了多个报文,只要有一个报文丢失了就会造成拼接失败,因为根本不知道哪个报文丢了(TCP不关心分片),补发就要全部补发,对整个报文进行重传。



猜你喜欢

转载自blog.csdn.net/qq_66314292/article/details/131794497
今日推荐