IP 协议

发布于:2025-06-26 ⋅ 阅读:(19) ⋅ 点赞:(0)

理解传输层和网络层

对于TCP/IP4层模型,我们目前已经搞定了应用层和传输层,接下来我们要学习的是网络层,也称为互联网层!

IP协议的核心作用和构成

IP协议提供了一种能力(有很大改了可以做到某种事情),把数据报从A主机,跨网络,送到B主机,我们暂时理解为主机A向主机B发送的IP报文,在路由器上,真正在网络当中进行传输的,我们短暂的认为是IP报文!IP报文是对TCP报文进行封装的!

这个能力就可以类比成张三很有概率考满分,是很有概率,张三的爸爸是教导主任,需要保证张三可以拿满分!如果没有考满分,就让全体的学生,包括张三在内进行重新考试!

  1. 所以,张三提供能力,也就是我们本篇所要讲的网络层,如IP协议1
  2. 张三爸爸提供策略,也就是我们前一篇学习的传输层协议,比如TCP协议,解决说如果丢包了怎么办?超时了怎么办?的问题,三次握手,流量控制等等策略!

通过能力+策略,那么数据报就可以100%从主机A传送到主机B!

也就是说:TCP/IP协议的核心功能就是100%把数据可靠的从主机A跨网络送到主机B

既然IP协议的能力是把数据报从主机A跨网络传送到主机B,所以就必须要有方式来表示通信两端的主机的唯一性!!!(那么每一台主机都必须设置唯一的IP地址(公网IP)!!!)(不仅仅是唯一性,还有网络划分相关的,这些补充后面会说)IP协议解决的就是主机到主机的问题!TCP协议往下是种可靠性策略,往上就是解决得另一个问题:进程到进程的问题,因为有端口号!

就相当于小明目前在福建,想要去北京故宫游玩。但是小明不能说坐飞机到故宫,这就有点奇怪了,是先坐飞机到北京,然后在北京内部,坐地铁到故宫! 所以在我们网络通信种,就必须要带出一种概念:未来会说到:我们必须要将发送的报文,发送到对应的目标主机的所在的局域网/子网当中。也就是说将发送的报文进行IP路由到主机C,但是不能直接到主机C,而是要先到达主机所在的子网,到达子网之后,然后在子网内部做对应的内网转发,达到主机C!

所以其实呢!IP = 目标网络(172.18.45) + 目标主机(153)(172.18.45.153)

路由的本质理解:路上的时候,本质是进行从一个子网进入到另一个子网!

  • 主机:配有IP地址,但不进行路由控制的设备;
  • 路由器:既配有IP地址,又能进行路由控制;
  • 节点:主机,路由器都是一个个节点。 

IP协议的报头

我们知道:协议就是结构体,在内核当中,对应的结构体是 struct iphdr:

在 Linux 系统中,struct iphdr 是用于表示 IP 数据报头的结构体,定义在 <linux/ip.h> 头文件中。以下是 struct iphdr 的主要内容:

struct iphdr {
    unsigned char   ihl:4;          // IP 头长度(以 32 位字为单位),通常值为 5(20 字节)
    unsigned char   version:4;      // IP 协议版本,通常为 4(IPv4   )
 unsigned char   tos;            // 服务类型(Type of Service),用于 QoS(服务质量)
    unsigned short  tot_len;        // IP 数据报总长度(包括头部和数据部分)
    unsigned short  id;             // 标识字段,用于分片重组
    unsigned short  frag_off;       // 片偏移和标志位(低 13 位为偏移量,高 3 位为标志)
    unsigned char   ttl;            // 生存时间(Time to Live),每经过一个路由器减 1
    unsigned char   protocol;       // 上层协议类型(如 TCP 是 6,UDP 是 17)
    unsigned short  check;          // IP 头部校验和
    unsigned int    saddr;          // 源 IP 地址(32 位)
    unsigned int    daddr;          // 目的 IP 地址(32 位)
    // 以下是可选的 IP 选项部分(如果 ihl > 5)
    // __u32         options[];     // IP 选项(可变长度)
};

从宏观上来说,基于TCP,我们一旦想要发送报文,就需要构建一个sk_buff,而sk_buff还需要为报文申请一块内存块(数据区),然后有对应的data,tail指针指向对应的头部信息,当刚开始构建出sk_buff的时候,data指向的只有数据(应用层数据),应用层将数据拷贝下来,然后添加TCP的报头,然后data指针往上指到TCP协议头部,如果sk_buff再往下一层交付,我们称为封装,data指针向上移动,移动 -=sizeof(IP报头)字节 (向下增长)然后将这一大块空间进行强转成对应的iphdr结构,这样就可以填充对应的IP报头信息了!这就可以进行封装过程了!

下面我们先来简单看看IP报头:

IP协议其实和TCP协议是很相似的,但整体来说没有TCP那么复杂:

IP协议报头的固定部分长度为20字节,如果包含可选的扩展选项,则总长度会超过20字节。以下是IP协议报头的结构及其字段说明:

字段名称 长度(位) 描述
版本(Version) 4 表示IP协议的版本号。IPv4的版本号为4,IPv6的版本号为6。
头长度(IHL) 4 表示IP头部的长度,单位为32位字(1字=4字节)。最小值为5(20字节)。
服务类型(TOS) 8 用于指示数据报的服务类型,包括优先级、延迟、吞吐量和可靠性等。
总长度(Total Length) 16 IP数据报的总长度,包括IP头部和数据部分,单位为字节。最大值为65535字节。
标识(Identification) 16 用于唯一标识主机发送的每一份数据报。在数据报分片时,所有分片的标识值相同。
标志(Flags) 3 用于控制数据报的分片行为。包含以下标志:
 
片偏移(Fragment Offset) 13 表示该分片在原始数据报中的位置,单位为8字节。
生存时间(TTL) 8 数据报在网络中可以经过的最大跳数。每经过一个路由器,TTL减1,当TTL为0时,数据报被丢弃。
协议(Protocol) 8 表示IP数据报携带的上层协议类型。常见的协议号包括:

 
校验和(Header Checksum) 16 用于检测IP头部在传输过程中是否发生错误。校验和只覆盖IP头部,不包括数据部分。
源IP地址(Source Address) 32 发送方的IP地址。
目的IP地址(Destination Address) 32 接收方的IP地址。
选项(Options) 可变长度 可选的扩展选项字段,长度可变。如果存在选项,则报头长度超过20字节。

面对IP报头,我们必须解决两个问题:

IP报文解包问题!IP报文分用问题!

未来我们收到IP报文,首要问题就是把报头和其有效载荷进行分离!第一,报头整体的标准大小是20个字节,可以先读取IP报文的前20个字节,我们就可以得到4位首部长度,假设是24字节,24-20=4字节,就是选项的内容,其中报头部分还有一个16位的总长度,通过总长度减去报头部分的大小,其余的就是有效载荷的大小了!我们就可以根据IP报头中的4位首部长度,来进行报头和有效载荷的分离!为什么还需要有总长度,是因为sk_buff对应的tail指针后面还有数据呢!

因此通过4位首部长度和16位总长度就可以解决IP报文的解包问题,分装问题我们也是可以理解了!

对于分用问题:我们把报头和有效载荷分离了,那么我们怎么知道IP报文携带的有效载荷是TCP还是UDP的呢?

其实在IP报头中,有一个字段 --- 8位协议!表明对应的上层协议是谁!因此我们就可以根据8位协议+4位首部长度+16位总长度来解决分用问题!

8位服务类型(Type Of Service): 3位优先权字段(已经弃用), 4位TOS字段, 和1位保留字段(必须置为0)。4位TOS分别表示: 最小延时, 最大吞吐量, 最高可靠性, 最小成本。这四者相互冲突, 只能选择一个。对于ssh/telnet这样的应用程序, 最小延时比较重要; 对于ftp这样的程序, 最大吞吐量比较重要。

第二行的内容我们暂时不作说明!

对于生存时间(TTL)字段,我们可以先来看一个样例:

我的主机ping百度,发现其 ttl 是50,那么这个 ttl 又是什么意思呢?

TTL(Time To Live)是IP数据包中的一个字段,用于限制数据包在网络中的存活时间或跳数。它的主要作用是防止数据包在网络中无限循环传播,从而避免网络资源的浪费和网络拥堵。

TTL的作用原理

当一个主机发送一个IP数据包时,会在数据包的IP头部设置一个初始的TTL值(通常为64、128或255)。每经过一个网络设备(如路由器),TTL值会减1。如果TTL值减到0,数据包就会被丢弃,并且发送一个ICMP超时消息回源主机,通知发送方数据包已被丢弃。这样可以确保数据包不会在网络中无限循环。

所以TTL的本质就是一个计数器,当我们对应的数据包经过一个路由器,该报文就会将其自己的TTL计数器做减减!计数器小于等于零的时候,报文就不被转发,而是被对应的路由器自动丢弃了!--- 最大报文生存时间!

为什么需要TTL

1. 避免网络拥堵

如果没有TTL机制,数据包可能会在网络中无限循环。例如,假设一个数据包因为路由配置错误而进入了一个环路,它会不断地在环路中转发,占用网络带宽。随着时间的推移,这样的数据包会越来越多,最终导致网络拥堵,甚至瘫痪。TTL机制可以有效避免这种情况,确保数据包在一定时间内被丢弃,从而释放网络资源。

2. 防止信号无限放大

在早期网络中,集线器(Hub)是一种简单的网络设备,它会将接收到的信号广播到所有端口。如果数据包没有TTL限制,它可能会在多个集线器之间不断转发和放大,最终导致网络性能下降。TTL机制可以限制数据包的转发次数,避免信号无限放大。

3. 避免“人走报文还在”的问题

在没有TTL的情况下,即使发送方和接收方的通信已经结束,数据包仍然可能在网络中继续传播。这就像一个人已经离开,但他的声音还在房间里不断回荡一样。TTL机制可以确保数据包在一定时间内被丢弃,避免这种“人走报文还在”的情况,从而提高网络的效率。

4. 优化网络性能

TTL还可以用于优化网络路径。通过设置不同的TTL值,可以检测数据包在网络中的路径长度,帮助网络管理员发现网络中的环路或性能瓶颈,从而优化网络配置。

为什么TTL值是50

上面图中的TTL值为50,这可能是因为网络路径较短,或者中间设备对TTL值进行了调整。一般来说,TTL值的初始值由发送方设置,常见的初始值为64、128或255。在经过多个路由器后,TTL值会逐渐减小。如果TTL值为50,说明数据包已经经过了大约15跳(64-50=14)的路由器转发。

总结

TTL机制是网络中非常重要的一个功能,它通过限制数据包的存活时间或跳数,避免了数据包在网络中的无限循环和无限放大,从而防止网络拥堵,优化网络性能,确保网络的高效运行。

16位首部校验和

这个首部校验和是和IP报文分片相关概念的,后面会说明!虽然IP协议并不提供可靠性的保障,但是也是也是需要确保至少向上层(TCP/UDP)交付的时候是正确的报文!因为报文在转发的时候,可能会因为电流-磁场的影响,导致比特位反转的问题,所以我们需要通过校验和来保证IP/TCP报文是正确的!

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

报文在路由的时候,是根据其IP报头中的源IP地址和目的IP地址来进行报文转发的!这也是我们之前写套接字的时候,要将字符串风格的点分十进制的IP地址,转化成4字节的网络序列,因为这是在IP报头协议当中。源IP地址和目的IP地址是32位的,又因为IP报头是报文的一部分,将来是需要发送到网络中的,所以必须转成4字节的大端序列!

理解子网划分

网络本身是几十年发展的产物。网络建设是经历了几十年的规划建设!--- 网络是被设计过的!那么在报文路由的时候,最核心的应该是理解网络如何被设计的!硬件决定软件,软件优化硬件!

网络被设计?我们就必须要来谈谈子网划分的问题!

为什么要子网划分?

举个例子,在我们大学生活中,每一个学生都有自己的对应学院的学号,我们现在就将学号的构成理解为:院号+所处编号

故事背景是这样的:张三是计算机学院的学生,院号是01,其编号是123,所以张三的学号是01123,今天张三捡到一个钱包,钱包只有学号信息06321,那么张三该如何归还钱包?

张三不一定清楚06是哪一个学院,但是张三一定可以确定该钱包不是计算机学院的,那么张三就一定可以判断清楚:丢钱包的一定不是计算机学院的学生!也就只有一个人 --- 院学生会主席!张三就在计算机学院的群@其院学生会主席,并将钱包的信息---学号和自己的电话号码打包提交,那么作为院学生会主席,就应该要知道06是哪一个学院的!那么其院学生会主席就将该信息从院群转发到校群,并且@机械学院的学生会主席。机械学院主席就接收到其信息,并转发到其机械学院的群里面去,这时候,这不是李四嘛!所以李四就接受到了这个消息,李四就通过消息上的电话,后续就是约着见面,归还钱包了!

  1. 在整个过程之中,学号被分为院号和编号,这就相当于IP地址,IP地址被划分成两部分,目标网络+目标主机。
  2. 那么计算机学院和机械学院就相当于一个一个的子网,而张三李四就对应着源主机和目标主机!
  3. 而各个院学生会主席就是从一个子网到另一个子网所对应的出入口 --- 路由器!
  4. 在计算机学院群中@学生会主席,并发送消息,这个过程称为内网转发!
  5. 院学生会主席通过校群,将消息发送给机械学院学生会主席,这叫做公网转发!
  6. 每一个学院对应的院号,我们称之为网络号!后面的编号就是主机号!

其中每一个学院的网络都叫做内网,或者局域网,校群就是公网!

在我们没有上大学的时候,上面的学院,院号等概念,已经被学校精心设计过了!那么此时现在的学校就相当于运营商(电信,联通,移动)!划分学院,对学院进行编号,形成院号!我们将这个过程叫做子网划分

IP 地址分为两个部分,网络号和主机号。

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

所以说,为什么需要子网划分?为什么学校要划分各种学院?

路由报文,本质就是查找主机的过程!IP协议的最核心内容就是查找目标主机!查找的本质其实是淘汰的过程!就比如二分查找,确定了在左半区域,那么对应的右半区域就是被淘汰的!换句话说:只要淘汰的效率越高,那么查找的效率也就越高!对于上面的例子,张三将信息交给其对应的学生会主席,其实就是淘汰了整个计算机学院的学生了!在由计算机的主席交给机械的主席就是淘汰了其他的学院的全部学生!后面交给李四就是淘汰了机械学院的其他无关的学生!

所以子网划分好之后,未来查找目标主机的时候,必须先查找目标网络(前面只关心06这个院号),本质就可以淘汰其他网络,可以在全网中提高查找目标主机的效率!

上图是两个不同子网下的IP地址情况!

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

我们可能会好奇说,在子网中,在内网环境下!,我们在家里的电脑没有连网的时候是没有真正的IP地址的,有的也是自己主机操作系统自带的,用来做本地通信的,我们将水晶头插上,或者连上家里的无线的话,那么该路由器就会给连接此路由器的机器自动分配IP地址!这种由路由器为家里的机器分配IP地址的做法是 --- DHCP协议(应用层协议:相当于在路由器上部署了一个DHCP的服务)!

所以路由器除了有路由的功能,还有构建子网的功能!虽然现在我们对于子网和公网还没有很准确的认识。

分类划分(了解即可)

过去曾经提出一种划分网络号和主机号的方案,把所有 IP 地址分为五类,如下图所示:

  • A 类 0.0.0.0 到 127.255.255.255
  • B 类 128.0.0.0 到 191.255.255.255
  • C 类 192.0.0.0 到 223.255.255.255
  • D 类 224.0.0.0 到 239.255.255.255
  • E 类 240.0.0.0 到 247.255.255.255 

这种划分方法称为分类划分法!

因为IP = 网络号 + 主机号!所以子网划分的本质就是把32个比特位进行划分,确定网络号有多少位!这就是分类划分法的思路! 

子网掩码

随着 Internet 的飞速发展,早期的 IP 地址划分方案的局限性逐渐显现。大多数组织都倾向于申请 B 类网络地址,导致 B 类地址很快被分配完毕,而 A 类地址却浪费了大量资源。例如,申请一个 B 类地址,理论上一个子网内可容纳 65,534 个主机,而 A 类地址的子网内可容纳的主机数更多。然而在实际网络架设中,很少会出现一个子网内有这么多主机的情况,没能用充分,因此大量 IP 地址被浪费。

针对这种情况,提出了新的划分方案,称为 CIDR(Classless Interdomain Routing,无类别域间路由)。CIDR 的主要改进包括:

  1. 引入一个额外的子网掩码(subnet mask)来区分网络号和主机号。

  2. 子网掩码是一个 32 位的正整数,通常以一串“0”结尾。(11111......00000)

  3. 将 IP 地址和子网掩码进行“按位与”操作,得到的结果就是网络号。

  4. 网络号和主机号的划分不再依赖于 IP 地址是 A 类、B 类还是 C 类。

后面,因为分类划分法的划分方法太简单粗暴了,所以就有了子网掩码的方案, 未来运营商申请好对应的公网IP,他的IP地址信息是要配置进自己架设的路由器,基站这样的设备当中。未来在我们的每一台路由器内部,它会配置上:IP地址,还要给该路由器配置上子网掩码,子网掩码是一串以特定0结尾的数字。

使用IP地址"按位与"上子网掩码就是网络号!那么该路由器直接连接的网络号就有了!

那么子网掩码存在的意义是什么呢?子网掩码存在的价值和分类划分又有什么关系呢?

对于分类划分,带来的是:比如说移动去申请B类IP,但是主机号只用到了6位,这不就非常让费了吗?子网掩码是形如 --- 11111.....0000的一串32位数字,我们可以通过设置子网掩码1的个数来重新设置网络号!这是利用"按位与"来实现网络号和主机号的大小,因为0"按位与"上任何数都是0,所以我们需要多少个主机号,我们就可以规定在后面有多少个0!所以子网掩码存在的最大的意义就是可以把分类划分的网络IP资源得到充分利用!!!

将来我们表示对应的IP地址时,我们比较习惯于:IP地址/子网掩码前为1的位数{网络号有多少位}:

192.168.32.1/24

不过主机号是全0和全F的代表:

  • 全0:整个IP就是表示网络号
  • 全F:广播地址

所以真正的主机号需要 '' - 2 '' !

分类划分和子网掩码并不冲突,他们是相互作用的!

运营商,内网,公网

特殊的IP地址

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

IP地址的数量限制

子网掩码本质上只是对IP地址使用的利用率提高了,并没有提高全球范围内IP地址个数的绝对上限!

我们知道,IP 地址(IPv4)是一个 4 字节 32 位的正整数,因此总共只有 2^{32}个 IP 地址,大约是 43 亿左右。TCP/IP 协议规定每个主机都需要有一个 IP 地址。但这是否意味着只有 43 亿台主机能接入网络呢?实际上,由于一些特殊 IP 地址的存在,可用数量远不足 43 亿。此外,IP 地址并非按主机台数配置,而是每个网卡都需要配置一个或多个 IP 地址(路由器)。

CIDR 在一定程度上缓解了 IP 地址不足的问题(提高了利用率,减少了浪费),但 IP 地址的绝对上限并未增加,仍然不够用。为此,有以下三种解决方式:

  1. 动态分配 IP 地址:仅给接入网络的设备分配 IP 地址。因此,同一 MAC 地址的设备每次接入互联网时,得到的 IP 地址可能不同。

  2. NAT 技术(后续会重点介绍)。

  3. IPv6:IPv6 并不是 IPv4 的简单升级版,而是两个互不兼容的协议。IPv6 使用 16 字节 128 位来表示一个 IP 地址,但目前 IPv6 还未普及。

私有IP地址和公网IP地址

网络是被宏观上分为公网和内网,内网也可以在一定意义下被称为子网,局域网!

公网:内网(子网,局域网) = 1 : n

如果一个组织内部组建局域网,IP 地址仅用于局域网内的通信,而不直接连接到 Internet (公网)上,理论上可以使用任意的 IP 地址。然而,RFC 1918 规定了用于组建局域网的私有 IP 地址范围,具体如下:

  1. 10.0.0.0/8:前 8 位是网络号,共有 16,777,216 个地址。

  2. 172.16.0.0/12:前 12 位是网络号,范围是 172.16.0.0 到 172.31.255.255,共有 1,048,576 个地址。

  3. 192.168.0.0/16:前 16 位是网络号,共有 65,536 个地址。

属于这些范围的 IP 地址称为私有 IP 地址,而其他不在这些范围内的 IP 地址则称为全局 IP 地址(或公网 IP)。

我们之前说的IP地址在全球内唯一,这是针对的公网IP!  

对于私有IP,有这样一个定义:在网络通信的过程中,私有IP不能出现在公网上!

我们任何普通人,直接接触的,根本就不是什么公网,我们直接接触的都是内网或局域网,或某种意义上的子网!

我们在给手机支付费用的时候,我们刷的是淘宝,是抖音,但是我们确是给移动交付,这是为什么?

我们一旦有了内网的概念,那么内网IP,就不会出现在公网上,路由器本身就具有构建子网的能力!什么叫做构建子网呢?答案是:在一个子网内部,给所有主机分配IP的能力!也就是说路由器可以使用一种范围的IP,给自己将IP分配上,同时给连入路由器的设备分配IP,和路由器在同一个网段,也就是网络号必然相同!所以这不就是构建子网了嘛!

路由器又被分为企业级路由器和家用级路由器:

  • 运营商路由器:已经配置了两个子网(10.1.1.0/24 和 10.1.2.0/24),分别连接不同的家用路由器。这种划分有助于隔离不同的网络流量,提高安全性和性能。

  • 家用路由器:每个家用路由器也配置了两个子网(例如,192.168.1.0/24 和 192.168.1.1/24)。这种划分可以进一步细分家庭网络,例如将家庭设备和访客设备分开。

运营商所用的子网是10*开头的,对应的网络号位数比较短,可以容纳的足够多的主机,而我们家用的IP地址都是192.168开头的,这种网络号足够长,主机数比较少,所以他用来构建中小型网路,而运营商用来构建大型网络!

WAN口IP作为外部接口标识(是对外的!):像这WAN口IP是公网IP(122.77.241.3),那么对应的这个路由器我们称之为:公网的出入口路由器!

比如现在要发送一个报文:

src:192.168.1.201/24 //源主机
dst:122.77.241.3     //目标主机

虽然源主机不知道122.77.241.3是谁,但是源主机知道,这个报文一定不是发给和本身处于同一个子网的另一台主机的!因为源主机拿着目的IP和子网掩码进行 "按位与" 发现自己的网络号是 192.168.1.0 而目标IP是 122.77.241.0 ,明显不是一个网段!这时候只能将这个报文交给家用路由器,家用路由器刚刚已经知道了该报文不是属于 192.168.1 了,对其相关的网段进行淘汰了,当前家用路由器所连的网路是 10.1.1.0/24 ,同样的道理,判断该报文并不是发送给运营商内网所对应的任何一台主机的,这时候直接将报文继续向运营商路由器进行交付,至此运营商出入口路由器拿到报文,通过公网转发,未来一定可以交给目标主机!所以从内网到公网,根本就没有那么复杂!

通过这种方式,WAN IP地址在家庭网络与广域网之间的通信中起到了桥梁的作用,确保了数据包能够正确地从互联网传输到家庭网络,以及从家庭网络传输到互联网。

上面说到:私有IP是不能出现在公网上的!这是为什么?

上面的报文发送给目标主机的IP是公网IP,那么这个过程是不是出错了?我们是将报文发送到目标主机上了,可是未来这个主机,我们就称是抖音吧,抖音请求之后,还需要将报文转回来!

内网IP是我们路由器构建出来的,所以对于内网IP是可能会出现重复,就比如家用内网IP都是198.168.1开头的,这肯定会有可能出现重复的内网IP的!

正因为内网IP地址可能重复,我们将报文就像上面报文转发,这么明晃晃的出去了,抖音接收到,报文转回来时,全网内会出现大量重复的对应内网IP地址的主机!这还怎么回来啊!

正是因为回不来,所以私有IP是不能出现在公网上的!

所以更加确切的讲是:内网IP是不能出现在公网上,也不能出现在另一个子网当中!所以家用路由器收到对应得报文之后,需要把内网报文的源IP地址用家用路由器的WAN IP进行替换:

src:192.168.1.201/24 ------> 10.1.1.2
dst:122.77.241.3     //目标主机

(每经过一个内网路由器,进行srcip的替换,替换称为当前路由器的WAN口IP!) 

src:192.168.1.201/24 ------> 10.1.1.2 ------> 122.77.241.4
dst:122.77.241.3     //目标主机

该报文一旦被推送至公网,未来一定可以路由到目标主机,目标主机得到之后,此时,私有IP就不存在了,最后一个出入口路由器所对应的WIN口IP一定是一个公网IP,所以站在目标主机的角度,是由一台公网主机,即公网出入口路由器给他发消息!这样私有IP就被屏蔽了!所以报文可以从内网通过运营商的出入口路由器到达公网!再到目标主机!

这样,公网的出入口路由器就是最后的一层了,这就保证了公网IP不会出现在公网当中了!

不过接收到报文的主机需要做应答,那么就必然要考虑 "原路返回" 的问题!如果要回来就一定要将应答报文推送到发送端所对应的运营商的出入口路由器(所对应的整个内网的路由器),可是转到对应的出入口路由器了,那么其内网当中有那么多重复的内网IP,那么该怎么正确回来呢?这个问题暂时先不说!我们在《NAT、代理服务、内网穿透》的时候会讲!我们目前只输出一个结论:报文回来的时候,一定能够把报文先给子网出入口路由器!剩下的工作就是运营商会使用一定的办法来将报文交给对应的主机!剩下的工作就是内网转发了!

简单说一说吧,就是路由器很强大,报文是如何做到内网转发的呢?其实发送端的内网IP在其所在的内网当中是唯一的,那么在发送报文的时候,走到对应路由器进行srcip的替换的时候,会在路由器内部建立替换之前的IP地址和替换之后的IP地址,未来反向的通过路由器中维护的映射表来实现! 

内网IP经过路由器WIN口IP替换的技术,叫做NAT(网络地址转化)!目前只是说了发送端主机发送的报文从内网出公网的过程,以及应答报文返回到对应出入口路由器的过程,我们还没有谈内网是如何转发的!

内网IP地址可能重复,并且因为有NAT技术,不影响内网向外网通信!所以,NAT可以解决IP地址不足的问题!!!

当用户账户出现欠费情况时,运营商会利用其网络管理系统对用户的网络连接进行控制。具体来说,运营商的网络设备(如路由器和交换机)会根据用户的账户状态来决定是否将用户的报文转发到公网。如果账户欠费,网络设备会检测到这一状态,并通过配置的策略阻止报文的转发。例如,路由器可以配置访问控制列表(ACL)来拒绝来自欠费用户的流量,或者将这些流量重定向到一个特定的提示页面,告知用户需要缴费。这样,即使用户的设备仍然连接到网络,也无法正常访问公网资源,直到用户完成缴费,运营商才会恢复正常的报文转发,允许用户重新访问公网。

这也是为什么我们刷抖音没流量是需要给移动等缴费!

如果我们发送的请求报文中含有敏感信息呢?就比如谷歌,对应的运营商路由器将该报文直接丢弃掉,这不就上不了嘛!这就使传说中的 "长城技术" --- "墙" !墙就在运营商那里!下面知识科普!可要科学上网!

我们呢是绕不过运营商的,只能骗过运营商,让报文遗漏出去! 

公网的理解

在公网中,一定使用的是公网IP,是国际标准化组织规定的,给各个国家的运营商自主申请的!运营商不仅仅要组织各个地区的内网环境,还要组件自己国家的公网环境!

一个区域,究竟能有多大的网络,取决于自己有多少个公网IP!分配公网IP不是简单的按照国家为单位的。而是根据入网的人口密度等相关指标的。

我们这里简单认为:公网IP划分的过程是在按照国家为单位的。

根据国家为单位,我们现在用IP地址前8位可以表示地区。各个国家都会有自己对应的网络号!而每一个国家有自己对应的网络号的同时,还必须得有自己国家之间的国际路由器!国际公网又是公网的一部分。

以我国中国为样例:

因为我们国家有34个省份,有很多个地区,所以可以再后面拿8个比特位作为我们省份的表示:

后面的省下的市一样可以往后面去规定划分!后面公网的对应的主机号就会越来越少,我们就可以以到达某一个限度,转而去使用内网环境!

我们也可以间接得出一个结论:公网路由器的路由表算法和内网的路由器的算法的复杂度是不同的!

路由

其实上面我们就已经讲过路由了,接下来我们来整合并丰富一下:

路由就是在复杂的网络结构中, 找出一条通往终点的路线!比如说从主机A到达主机B!

主机A要将报文发送给主机B,这个过程是逐跳(Hop-by-Hop)进行的。报文在传输过程中会经过多个中间网络设备,如路由器。每个路由器都有自己的路由表,当报文到达一个路由器时,该路由器会提取报文中的目的IP地址,并根据路由表中的信息来决定将报文转发到下一个跳(即下一个路由器或最终目标)。

路由表的作用

路由表是路由器内部的一个数据结构,它包含了以下关键信息:

  • 目的网络地址:报文要到达的目标网络的IP地址。

  • 子网掩码:用于确定目的IP地址属于哪个网络。

  • 下一跳地址:报文应该被转发到的下一个路由器的IP地址。

  • 出接口:报文应该从哪个接口发送出去。

缺省路由

除了具体的路由条目外,路由表中还可以包含一个缺省路由(Default Route)。缺省路由是一种特殊的路由条目,用于处理那些在路由表中没有明确匹配项的报文。它的目的网络地址通常是0.0.0.0,子网掩码是0.0.0.0,表示“所有其他网络”。

当路由器收到一个报文,且该报文的目的IP地址在路由表中没有明确匹配的条目时,路由器会使用缺省路由来转发该报文。缺省路由通常指向一个默认的网关,这个网关通常是连接到更广泛网络(如互联网)的路由器。

假设主机A的IP地址是192.168.1.100,它要发送一个报文到主机B的IP地址8.8.8.8。主机A的路由器有以下路由表:

目的网络地址 子网掩码 下一跳地址 出接口
192.168.1.0 255.255.255.0 - eth0
0.0.0.0 0.0.0.0 192.168.1.1 eth0
  • 第一条路由:用于本地网络192.168.1.0内的通信。

  • 第二条路由:缺省路由,用于所有其他网络的通信。

当主机A发送一个报文到8.8.8.8时,路由器会检查路由表:

  • 8.8.8.8不属于本地网络192.168.1.0,因此没有明确匹配的路由条目。

  • 路由器会使用缺省路由,将报文转发到192.168.1.1(默认网关)。

通过这种方式,报文最终可以到达更广泛的网络,直到找到通往目标主机B的路径。但是真正目的不是到达对应网络。而是还需要通过内网转发达到对应网络种的目标主机B!

所以最终查路由表得到的结论往往有如下三种:

  • 查找到,知道下一跳要去哪里;
  • 查路由表没查到,直接进行default进行缺省路由;
  • 我们当前已经达到了当前网络所在的出入口路由器,我们转而进行内网转发!

我们自己的计算机电脑内部本身就有网络层的,所以电脑内部本来就有路由表条目!下面是我自己的元服务器机器上所对应的路由表条目,使用Linux命令:

route

进行查看: 

我们假设下面是一个整整的路由表的信息:

Destination Genmask Gateway Iface Flags
192.168.10.0 255.255.255.0 0.0.0.0 eth0 U
192.168.56.0 255.255.255.0 0.0.0.0 eth1 U
0.0.0.0 0.0.0.0 192.168.10.1 eth0 UG

示例1:目的地址为192.168.56.3

与第一行条目匹配

  • 目的地址192.168.56.3与子网掩码255.255.255.0做与运算,结果为192.168.56.0

  • 与第一行的目的网络地址192.168.10.0不匹配。

与第二行条目匹配

  • 目的地址192.168.56.3与子网掩码255.255.255.0做与运算,结果为192.168.56.0

  • 与第二行的目的网络地址192.168.56.0匹配。

  • 由于192.168.56.0/24是与eth1接口直接相连的网络,因此可以直接从eth1接口发送到目的主机,不需要经路由器转发。


示例2:目的地址为202.10.1.2

依次与路由表前几项进行匹配

  • 目的地址202.10.1.2与子网掩码255.255.255.0做与运算,结果为202.10.1.0

  • 与第一行的目的网络地址192.168.10.0不匹配。

  • 与第二行的目的网络地址192.168.56.0不匹配。

按缺省路由条目处理

  • 按照缺省路由条目(第三行),从eth0接口发送出去,发往192.168.10.1路由器。

  • 192.168.10.1路由器根据它的路由表决定下一跳地址。

路由表生成算法指南

路由表可以由网络管理员手动维护(静态路由),也可以通过一些算法自动生成(动态路由)。后面可以自己调研一些相关的生成算法,例如距离向量算法、LS算法、Dijkstra算法等。

协议字段补充

我们接下来就是要将上面没有谈到的三个字段,是什么?为什么?怎么办?谈清楚了!

目前我们已经搞定了应用层,传输层了,目前网络层也粗力度了解了,接下来就是要进行对数据链路层的理解了!现在我们直接提出一个概念:数据链路层有一个规定:数据链路层从上层接受下来的完整报文,大小不能超过MTU(最大传送单元),该值对应的标准大小是1500字节,这是为什么我们后面数据链路层会说明的! 

如果报文大小超过了MTU,那么改报文就需要在网络层进行分片!分完片之后,达到目标主机的网络层中,可能就要把多个分片再进行组装,形成一个报文!(谁分片谁组装,谁污染谁治理!)

所以结论:IP报文可能要进行分片和组装!

分片的坏处:

在网络层本来是一个报文的,现在需要向下交付,需要遵守数据链路层的规则,就需要进行分片,那么就导致一个报文被拆成三部分,然后分别交给数据链路层,数据链路层就要转发三个报文了,但是到对端目标主句之后,对端还需要全部收到,然后再组装再交给上层,很明显情况变复杂了!

如果对端要收到的三个报文中一个丢了,就不可以进行组装了,也就不能进行向上交付了,站在下传输层角度,就是整个报文传送失败了,也就是说任何一个分片丢失,就表示整体报文整体分片丢失!!!然后呢?

如果上层是TCP协议,就会触发TCP进行可靠性保障们进行丢包重传,无所谓,但是UDP的话,那么报文就是真的丢了!

几个例子,C到S的主机报文丢包率是1%,可是分片分成了10分,每一个都是一个独立的IP报文了,那么这个时候,就需要保证对端S需要将这10个片全部收到才算做是报文完整的真正被收到!可是这个真正手收到的概率就是({99\%})^{10}

这就体现了分片的坏处:如果过多分片,在网络中就会增加报文的丢包概率!!!

这也说明:分片和组装不是主流,是被迫而为之!所以报文丢失的情况又增加了一种:可能是"报文分片"丢失了!

所以我们就需要减少分片!因为分不分片并不是直接由IP报文本身说了算的,IP报文的大小直接来源是上层,就像公司老板要求产品经理,只要成果的,并不关心下面的数据链路层可以接收的大小!那么只能在IP层进行报文的分片了。

这样对大家都不好,就需要减少分片,减少分片的本质就是在传输层!!!TCP都叫做传输控制协议了!所以数据一次发多少,出错了怎么办,一切都是由传输层来决定!所以传输层交给网络层的报文量不要太大,不要让IP报文超过1500字节不就不会发生分片了嘛!

传输层交给IP的报文多大的时候,IP不会分片???

传输层无非就是从缓冲区拿一部分数据,然后添加上TCP的报头,形成传输层对应的数据段,再向下交付给IP层,IP层再添加上对应的IP报头,形成IP报文,交给下一层数据链路层!我们现在按照标准长度来算:

TCP和IP报头的标准长度都是20个字节,所以传输层将发送缓冲区的数据单词发送的数据量不要超过1460字节!我们将1460字节称为MSS(最大段尺寸)

这也就是为什么在TCP当中的滑动窗口里窗口大小是拥塞窗口和对端接受能力的最小值!我们就按照滑动窗口是对端的接受能力,接受能力是5000字节,那么滑动窗口的大小就是5000字节,好奇说为什么不将所有的报文打一个包,再整体发送过去?!反而要拆成一个一个区再发过去:

这不就是因为数据链路层的MTU相关规定,底层不能一次发送超过1500字节,本质原因就是为了减少分片! 

我们不建议作分片,但是IP包头中却赫然包含相关分片的字段,虽然分片和组装不是主流,所以我们需要学习如何分片和组装!一个IP报文分片和组装就是和下面这三个字段有关的!

16位标识:每一个完整报文都有自己唯一的一个16位标识,不同报文标识不同!相同分片,标识相同! 

3位标志字段:

  • 第一位:保留(目前暂不使用,但未来可能会用到)。

  • 第二位:若置为1,则表示禁止分片。此时,如果报文长度超过MTU,IP模块会丢弃该报文。

  • 第三位:表示“更多分片”。如果进行了分片,最后一个分片置为0,其余分片置为1,类似于一个结束标记。说人话就是为1的话就是当前报文对应的切割的分片不是完整报文的最后一个分片,如果是0的话,就表示该报文对应的切割的分片是属于原本完整分片的最后一个分片!

13位分片偏移(Fragment offset): 表示分片相对于原始IP报文开始处的偏移,即当前分片在原报文中的位置。实际偏移的字节数是该值除以8得到的。因此,除了最后一个报文(如果前面的报文长度都是8的整数倍,那么最后一个分片的偏移量也一定是8的整数倍)之外,其他报文的长度必须是8的整数倍,否则报文将不连续。

假设有一个原始IP报文,总长度为4000字节(不包括IP头部),网络的MTU为1500字节(不包括IP头部),需要对该报文进行分片处理。

举个样例:

分片编号 实际长度(字节) 分片偏移(字节) 偏移值(偏移字节数除以8) 更多分片标志
1 1500 0 0 1
2 1500 1500 188 1
3 1500 3000 375 1
4 500 4000 500 0
  • 分片偏移:表示当前分片在原始报文中的起始位置。

  • 偏移值:分片偏移除以8得到的值,用于IP头部表示。

  • 更多分片标志:1表示后面还有分片,0表示这是最后一个分片。

  • 长度要求:除最后一个分片外,其他分片长度必须是8的整数倍,以确保报文连续。

所以,我们该如何理解分片和组装呢?

先来说说组装吧!今天收到很多的IP报文,第一件事情是什么?不仅仅是只有我一个人在访问目标服务器,还有张三,李四,王五等等,来自不同用户发送的报文,有的是分片的,有的不是分片的!所以第一步是需要甄别出来特定报文是否被分片了!这是第一个问题!假设收到100个报文,目标主机就需要对这100个报文的每一个报文进行准确判定!没分片就继续向上交,分片了就等一等。报文没有被分片就直接向上交付即可,但是如果分片了,那么第二个问题就是:如果报文直接进行分片了,目标主机怎么保证将所有的分片都放在一起?知道哪些报文分片拿全了,第三步就需要进行对分片报文的组装了!

其实只要将第一第二步理清楚了,那么第三步也就是一二步的结果了!

对于第一个问题:我们怎么甄别出来特定报文是否被分片了?

如果更多分片标志位为1,那么就代表这个报文是分片报文,可是要是报文分片了,分片报文更多分片标志位为1的丢了,只剩下更多分片的标志位为0的一个分片报文被收到,这该怎么办,直接向上交付吗?不用怕,我们还有一个13位分片偏移,最后一个分片报文的13位分片偏移不为0!所以其反面,也就是报文没分片就是:更多分片==0&&片偏移==0!

//报文没有被分片
更多分片==0&&片偏移==0

//报文被分片
!(更多分片==0&&片偏移==0)

 对于第二个问题:如果报文直接进行分片了,目标主机怎么保证将所有的分片都放在一起?

一旦知道该报文是分片报文,我们就可以立马提出一个16位独立标识!我们就可以根据相同的标识分片,将其聚合在一起!但是重要的问题是我们怎么知道我们将分片报文收集全了呢?我们先来看看收不全的情况:下面是基本情况,实际往往更加复杂,甚至全丢!全丢也就不会走到这个问题上。

  • 第一片丢失(没有见到片偏移为0对应标识的分片报文)
  • 中间片丢失(起始报文所对应的偏移量加上自身报文长度就是下一个分片报文对应的偏移量,所以我们可以将收到的所有相同独立标识的分片报文按照片偏移进行升序排列,采用IP报文的片偏移 + 自身长度 = 下一个分片的片偏移数字)(这是针对中间部分的分片报文的!)
  • 结尾片丢失(更多分片标志位没有为0的对应标识符的分片报文)

对于最后一个问题:目标主机保证将所有的分片都放在一起了,接下来该怎么组装?

只需要将收到的保证全部对应分片收到的所有的分片报文进行按照片偏移进行升序排序就可以组装称为一个完整的报文了! 

我们现在知道怎么组装了,对于分片呢?

根据组装的理解,其实分片就是在对完整报文进行分片的时候添加上上面三个关键字段!

更多细节后面会在加餐中说明!!!


网站公告

今日签到

点亮在社区的每一天
去签到