July.cc Blogs

本篇文章

手机用户建议
PC模式 或 横屏
阅读


Linux网络 2024 年 9 月 4 日

[TCP/IP] 网络层代表协议--IP协议介绍(1): IP协议 数据格式、... 简单介绍

TCP/IP 四层协议模型, 前面的文章, 已经通过介绍具体协议了解了前两层的功能:
  1. 应用层: HTTPHTTPS

    [TCP/IP] 初识应用层协议: 序列化与反序列化、编码与解码、jsoncpp简单食用…

    [TCP/IP] 应用层代表协议—HTTP协议 以及 HTTPS协议 分析合集

  2. 传输层: TCPUDP

    [TCP/IP] 传输层代表协议—UDP协议介绍 合集

    [TCP/IP] 传输层代表协议—TCP协议介绍 合集

本篇文章分析网络层代表协议: IP协议, 只以ipv4做介绍

IP协议

TCP/IP协议栈中:
  1. 应用层:

    主要做数据的处理工作, 包括: 序列化/反序列化, 协议处理, 分析读取完整报文等

  2. 传输层:

    TCP协议需要实现的最重要的工作是 保证数据在网络中传输的可靠性

那么网络层呢?
传输层封装的数据是要交付给网络层的, 网络层要实现的目的实际上也只有一个, 即 让主机A 拥有能将数据 从主机A发送到主机B的能力
网络中一定是存在多主机的, 所以数据发送到网络中以后, 一定需要能够达到目标对端主机
而, 网络层IP协议就可以让主机拥有这样的能力
当主机B要向主机C发数据, 通过IP协议, 主机B就能将数据通过网络”传送”到主机C中
数据, 会在不同的路由器之间进行转发, 直到找到目的主机

主机: 拥有IP地址, 但不做路由控制的设备(有能力, 但不做)

路由器: 拥有IP地址, 并做路由控制的设备

节点: 网络中主机和路由器的统称

但是, IP并不提供传输可靠性的保障, 数据在网络中传输的可靠性是TCP协议实现的, 所以 想要数据可靠的传输到对端主机就需要结合TCP协议与IP协议
下面就来介绍一下, IP协议

IP协议格式

TCP协议相同, IP协议 以ipv4报头的标准长度为20字节:
分析一下ipv4协议报头的字段:
  1. [0, 3]: 4位版本, 用以区分IP协议的版本, 现在熟知的就是ipv4ipv6, 此字段就是用来区分协议版本的

    不得不说, 协议的设计者是真的有前瞻性, 早早的就将区分版本的字段给留了出来

  2. [4, 7]: 4位首部长度, 用于记录当前报头大小, 4位可表示0~15, 计算报头大小时 要*4, 所以报头大小范围为: 20~60字节

  3. [8, 15]: 8位服务类型(TOS)

    其中, 前三位[8, 10]为优先权字段, 但已经弃用

    [11, 14]为TOS字段, 只允许最多有一位设置为1, 分别表示: 最小延时, 最大吞吐量, 最高可靠性, 最小成本

    [15]保留字段, 没有使用

    此字段一般不需要进行设置, 除非真的有需求

  4. [16, 31]: 16位总长度(字节), 用于记录当前报文大小

  5. [32, 47]: 16位标识, 起 报文分片标识作用 (后面介绍)

  6. [48, 50]: 3位标志, 起 报文分片标志作用, 第一位保留不用 (后面介绍)

  7. [51, 63]: 13位片偏移, 起 报文分片整理作用 (后面介绍)

  8. [64, 71]: 8位生存时间(TTL), 标识IP报文在网络中的最长生存时间

    当数据被发送到网络中之后, 数据会经过许多次的路由转发

    正常情况下, 经过许多次的路由转发, 数据可以正常的被对端主机接收到

    但是在不正常的情况下, 可能因为一些情况对端无法接收数据, 数据可能在网络中不断路由, 即 数据在网络中游离. 此时, 就需要将数据丢弃掉, 防止占用网络资源

    此字段, 即 表示数据可在网络中路由转发的最长次数

    不可过大, 不可过小

  9. [72, 79]: 8位协议, 用于表示上层(传输层)使用协议

  10. [80, 95]: 16位首部校验和, 用于校验协议报头是否损坏

  11. [96, 127]: 32位源IP地址, 记录发送方主机IP地址, 很重要的字段

  12. [128, 159]: 32位目的IP地址, 记录目的主机的IP地址, 很重要的字段

  13. 至此, 一共[0, 159]位, 20字节, 即 ipv4首部标准长度为20字节

  14. 可能: [160, ...]: 选项, 一般情况下不会使用, 具体选项 具体分析

TCP/IP协议栈, 同主机不同层级之间传输数据, 存在三个操作: 封装、解包、分用

关于这三个操作的概念:

  1. 封装:

    TCP/IP协议中, 当上层需要将数据发送到下层时, 就要对数据进行封装

    封装, 即 在有效数据之前添加所用协议的报头

    然后, 才会将封装好的数据交付给下一层

  2. 解包:

    TCP/IP协议中, 当对端主机接收到完整数据时, 会对数据进行解包

    解包, 即 对接收到的数据, 将数据中 同协议的报头部分解析并去除掉

    比如, 如果传输层使用TCP协议发送数据, 那么接收方的传输层接收到数据之后, 会分析数据的TCP报头, 并将有效载荷(不包括协议报头的数据部分)提取出来

    然后, 才会将有效载荷交付给上层

  3. 分用:

    TCP/IP协议中, 当对端主机需要将数据从下层交付到上层时, 需要进行分用

    分用, 即 将有效载荷交付给上层中指定的协议, 因为相同协议才能正确处理数据中的协议报头

    因为, 同一层中会存在很多不同的、使用场景不同的协议, 所以需要解析出需要数据封装时所使用的协议, 才能将数据交付给上层

IP协议报头中:
[4, 7]位字段: 4位首部长度, 可以有效解决封装与解包的问题, 这个字段表示协议报头大小, 所以可以将数据中 协议报头有效解析出来, 进而可以解包
[72, 79]位字段: 8位协议, 可以有效解决分用的问题, 这个字段存储的内容是上层所使用的协议, 所以在向上层交付数据时, 读取此字段就可以解决分用问题

IP协议的分片

绝大多数的字段, 简单介绍下功能就能过理解字段的实际意义
不过有几个字段需要在解释一下:
这三个字段是比较重要的, 不过在解释作用之前, 要先了解一个概念: 分片
分片, 即 如果传输层交付过来的数据较大, IP协议会对传输层交付过来的数据进行分割, 并 会分别对分割出来的数据进行封装. 这个行为被称为分片
为什么会进行分片呢?
原因是, 数据链路层 因为物理设备问题, 会对数据的大小进行限制, 如果网络层交付的数据超出了限制大小, 数据链路层会直接将网络层交付的数据丢弃
所以, IP协议如果收到的上层数据过大, 就会对数据进行分片
而, 分片的存在就会造成一些问题: 对端主机也会收到分片, 对端主机如何确认数据是否分片? 如何确认分片数据之前是否属于同一数据? 如何确认已经完整的收到了同一数据的所有分片? 如何对已经分片的数据进行还原?
而这四个问题的答案, 都在这三个字段上
  1. 对端主机 如何确认数据是否分片?

    IP协议需要对数据进行分片时, 会对分片数据的IP协议报头的[48, 50]: 3位标志的对应位, 进行填充

    [48]位, 保留位 不被使用

    [49]位, 如果此位被设置为1, 表示禁止IP协议对数据分片. 此时, 当数据过大时, 将会被直接丢弃

    [50]位, 用以表示 是否有更多分片. 当 此位被填充为1, 表示后面还有更多分片, 同时也表示当前数据为分片数据. 当此位被填充为0, 表示后面没有更多分片 或 表示此数据为非分片数据

    是否有更多分片是什么意思呢?

    当, IP协议对数据进行分片时, 会按照分先后顺序对数据进行分片

    如果, IP协议接收到6230字节的上层数据, 就会对数据进行分片, 可能会将[0, 1023] [1024, 2047] [2048, 3071] [3071, 4085] [4096, 5119] [5120, 6143] [6144, 6229]字节的数据, 均进行封装, 分片为个7最大不超过1500字节的IP数据报

    那么对于前6个分片数据, IP协议报头的第[50]位, 会被填充为1, 最后一个分片数据的 则会被填充为0

    所以, 当读取到IP协议报头的第[50]位为1时, 就说明还有属于同一数据的分片报文

  2. 对端主机 如何确认分片数据 之前是否属于同一数据?

    [32, 47] 16位标识, 就是用来标识 分片数据原来所属的数据的

    如果, IP协议需要对接收到的数据进行分片, 就会将这些分片的16位标识 均填充为相同的值

    这样, 对端主机读取时, 就能够识别到分片数据 所属的原数据

  3. 对端主机 如何确认已经完整的收到了同一数据的所有分片?

    首先, 对端必须接收到 报头第[50]位为0的分片数据

    然后就要根据[51, 63] 13位片偏移 确认是否有分片数据丢失了

    [51, 63] 13位片偏移, 填充的是 分片之后的数据首位置 相对 于原数据首位置的偏移量/8

    根据偏移量是否连续, 就可以确认是否完整的收到了同一数据的分片

    因为, [51, 63]为填充的是分片偏移量/8

    所以, 除了最后一个分片, 前面分片的大小需要为8的倍数

  4. 对端主机 如何对分片数据进行还原?

    根据[51, 63] 13为片偏移 进行还原

这是[32, 47]: 16位标识 [48, 50]: 3位标志 [51, 63]: 13位片偏移三个字段的作用, 均与分片有关
但, 分片是一种不好的行为
因为, IP协议并不能保证数据可靠性, 当对端主机 没有收到任意一个分片数据, 就会将其他所有 所属同一数据分片全部丢弃
这就意味着, 一旦对数据进行分片, 数据的丢包率就是所有分片丢包率的和, 即 分别越多 丢包率越高
所以, 一般情况下, 最好不要让IP协议对数据进行分片
但也不是直接禁止分片, 而是减少上层交付数据的大小, 所以 可以在传输层控制一下交付数据大小的上限

子网划分**

IP地址

IP地址, 在网络中是用来确定主机的
常规情况下, 每一台接入网络的主机都需要有一个唯一的IP地址, 这样能够在网络中确认唯一的主机, 然后才能通过IP地址实现不同主机之间的通信
ipv4协议的IP地址为4字节, 日常通过点分十进制的方式表示, 比如: 192.168.5.111 , 点分十进制表示IP地址, 每个点将分隔8位数据
所以192.168.5.111实际表示的是 11000000 10101000 00000101 01101111, 刚好四个字节
IP地址的这四个字节, 由两部分组成: 网络号 + 主机号. 网络号用于标识两个不同的网段, 主机号用于标识同一网段中的不同主机
网络号占用的位数越少, 主机号就越大, 就说明此网络中可以容纳的主机数就越多, 网络也就越大
比如, 192.168.5.111, 如果前24位都由网络号占用, 那么最后8位就由主机号占用, 那么192.168.5的这个网络中, 最多可以有0~255台主机
在网络中, 不同的主机是如何通过IP地址来快速地相互找到的呢?
网络中会存在许多的主机, 当两个主机需要发送数据时, 一定是知道双端主机的IP地址的
IP地址, 由两部分组成: 网络号 和 主机号
网络号是用来表示不同的网络的, 当数据被发送到网络中, 数据会在网络中的路由器之间路由
因为路由器也拥有自己的IP地址, 所以路由器也能够接收数据, 并且路由器会根据数据的IP报头中的 目的IP地址的网络号进行转发
网络号就像身份证的前6位一样, 是可以表示地区等信息的. 所以, 路由器之间进行网络信息同步之后, 是可以快速有效地进行数据转发的, 可以使数据快速的接近目标网络
直到数据被转发到目标网络之后, 再在网络内部 通过主机号找到目标主机

为什么路由器 通过网络号找目标网络 可以更快速地找到目标主机?

因为, 找目标网络可以按照网络排除一批主机, 而不是一个一个主机对比

IP划分方式

IP由两部分组成, 网络号和主机号
ipv4IP地址也就32位, 最多有256*256*256*256(4,294,967,296)IP地址, 并且是全球共用的
为了有效的、不浪费的使用IP地址, IP的网络号和主机号是有划分方式的
过去有一种划分方式, 将IP地址分为了5类:
  1. A类, 前8位为网络号, 且必须最高位必须为0

    包含IP地址为: 0.0.0.0127.255.255.255

    后24位为主机号, 那么A类网络中, 可包含主机数: 256*256*256(16,777,216), 用于大型网络

  2. B类, 前16位为网络号, 且最高两位必须为10

    包含IP地址为: 128.0.0.0191.255.255.255

    后16位为主机号, 那么B类网络中, 可包含主机数: 256*256(65536), 用于中型网络

  3. C类, 前24位为网络号, 且最高三位必须为110

    包含IP地址为: 192.0.0.0223.255.255.255

    后16位为主机号, 那么B类网络中, 可包含主机数: 256, 用于小型网络

  4. D类, 不做日常使用, 用于组播通信, 最高四位必须为1110

    包含IP地址为: 224.0.0.0239.255.255.255

  5. E类, 一般不用, 最高五位必须为11110

    包含IP地址为: 240.0.0.0247.255.255.255

前三类中, 需要哪一类, 就申请哪一类
此方法, 这会导致大量IP被浪费, 因为一申请A类B类, 就至少是65536IP
但实际上, 一个网段中通常是用不到这么多IP的. 被申请过的网络号又不能给其他人用, 所以就会造成很多IP浪费
所以, 就有了另外一种划分网络号和主机号方式, CIDR(Classless Interdomain Routing):
  1. 引入一个叫 子网掩码(subnet mask) 的东西, 划分网络号和主机号;

  2. 子网掩码是一个32位正整数, 子网掩码 由高位开始置1, 如果高位有N个1, 就表示对应IP高N位为网络号

    比如

    若存在IP以二进制表示: 11000000 10101000 00000101 10011101(192.168.5.157)

    若其高位前24位为网络号, 那么对应的子网掩码就应该是:

    11111111 11111111 11111111 00000000, 高24位置1

  3. 如果直到IP地址 和 子网掩码, 要求获取IP地址的网络号, 就可以 IP地址 & 子网掩码 计算

    子网掩码还有一种方式表示, IP/子网掩码位数

用子网掩码的方式划分IP, 与A、B、C类IP无关

子网掩码划分的优点

使用子网掩码相比类别划分, 有什么优点呢?
  1. 使用子网掩码, 可以更细化地划分IP地址

    比如 最小可以划分出 只有两台主机的网段, 只需要将子网掩码设置为11111111 11111111 11111111 11111110, 即 前31位是网络位

    那么, 一个网段中 最多只有两台主机

  2. 使用子网掩码, 可以更灵活地划分子网IP地址

    如果是类别划分, 就只有那三种类别可以在日常中使用, 网络号就只有8位、16位和24位三种情况

    而使用子网掩码划分, 可以随意地在合法范围内划分网络号的位数, 从1位到31位都可以

IPv4地址的限制

IPv4协议的IP地址是32位的, 最多也就40多亿的IP地址
而早在2021年, 全球的网民数量实际已经达到惊人的约49.7亿, 这只是网民数量, 还没有算上实际的设备数量
特别是 现在的移动互联网时代, 每个人手中可能有多部手机, 所以需要连接网络的设备远远不止49.7亿
再加上一些特殊的IP并不会被设备联网使用:
  1. 0.0.0.0, 代表当前主机所在的整个网络
  2. 127.*, 用于本机IP地址环回, 通常为127.0.0.1
  3. 255.255.255.255, 即 IP地址的32位全设置为1, 表示广播地址, 当向此IP发送数据时, 表示向同一子网中的所有主机发数据
即使 CIDR大大减少了IPv4地址的浪费, IP地址好像也完全不够用
不过, 有三种办法可以缓解这种情况:
  1. 动态分配IP地址

    即, 在设备不接入网络时 不分配IP地址, 在接入网络时, 动态分配IP地址

    所以, 同一个网卡设备, 每次接入网络时, IP可能并不会相同

  2. 使用IPv6协议

    IPv6协议的IP地址是128位的, IPv6地址的数量级是 10的38次方, 而IPv4只有10的9次方

    IPv6号称可以给地球上的每一粒沙子都分配一个IP地址

    所以, 使用IPv6好像可以没有后顾之忧的解决IPv4地址不足的情况

    不过, IPv6还没有完全发展起来, 并且与IPv4完全不兼容


    但是, 为什么现在绝大多数还是使用的IPv4呢?

  3. NAT技术*

公有IP和私有IP**

公有IP是连接在全球互联网上的IP, 在全球范围内是唯一的
私有IP则表示内部网络的IP, 不直接在全球公有互联网中进行路由. 不同的内部网络中, 私有IP地址是可以重复的
理论上, 私有IP的地址可以是任意的, 但RFC 1918规定了用于组建局域网的私有IP地址, 只能为一下这些:
  1. 10.*, 至少前8位为网络位
  2. 172.16172.31, 至少前12位为网络位
  3. 192.168.*, 至少前16是网络号
在这三个范围内的, 均被称为私有IP. 在公网中, 是看不到这三个范围的IP
即, 只要见到这三个范围内的IP地址, 就可以确定此IP是私有IP
比如:
172.19.4.141/20就是本机的私有IP, 前20位是网络号, 后12位是主机号
因为, 私有IP在不同的网络中可以重复, 即 这里一个网络中可以有 192.168.5.111, 另一个网络中也可以有 192.168.5.111, 只要能让私有IP也能够与全球的互联网通信, 就能够很大程度上解决IP不足的问题
NAT(Network Address Translation)就是 使用 公有IP结合私有IP 解决IPv4协议的IP不足的问题的

NAT技术

NAT(Network Address Translation) 网络地址转换