IP 协议

前言

前面已经梳理了同处于网络层的ARP地址解析协议和ICMP控制报文协议。这些协议都是为了辅助网络层最核心的IP协议而诞生的。网络层的IP协议可以说是整个TCP/IP协议栈的“半壁江山”,是构建起互联网环境的重要一环。

什么是IP协议

IP协议又叫作网际协议,核心定位是负责将网络数据包从源主机端尽可能的运送到目标主机端。IP协议有一个很特殊的地方:位于网络层上接TCP/UDP等高层协议,下接Ethernet等底层通信链路,这就体现了IP协议一个很重要的作用——屏蔽底层不同链路的实现差异,为协议上层及应用层提供统一的标准接口。

需要知道,网络底层链路不只有Ethernet以太网一种,老式的PPP拨号上网、Wi-Fi、移动网络(4G/5G)等等这些都是不同的底层链路协议,而不同协议之间根据适用场景不同往往差距是比较大的。如果没有IP协议,那么上层需要为每一个网络链路定制一套自身的逻辑,类似于这种:

HTTP on Wi-Fi.

HTTP on Ethernet.

HTTP on 4G/5G.

….

这显然不规范,而且没有统一标准各自实现起来十分复杂。

而IP协议正好解决了这个问题:IP协议通过IP地址统一了整个自网络层之上的行为,上层在发送数据包时并不需要关心自己底层处于什么网络链路,只需要将包交给协议栈就行;协议栈规定了统一的数据帧格式,不管底层处于什么链路,怎么去路由,反正帧格式是定死了的,拆掉外壳,里面永远是同一个IP数据报。


IP协议特点

IP协议是无连接不可靠的,发送端随时可以发送数据,接收端也随时可能接收到数据。不管是数据的发送还是接收,每一个数据包都必须带有独立的IP头以及IP地址信息。IP协议不保证数据能够正确送达对端,出错之后尽可能返回ICMP控制报文由上层来决定下一步;就算送达了也不保证顺序。

这里要强调一点:一定要正确区分IP地址和MAC地址的行为。IP地址用于在网络环境中逻辑定位通信双方,是跨网段寻址的依据,而MAC地址是底层网络链路中路由数据包的依据。下面以一个例子来讲讲IP与MAC的工作流程:

两个路由器都连接到多个网段,因此网卡接口也有多个(一个接口一个MAC地址)。

  • 主机H1在发送网络数据包之前发现对方H2并不处于同一网段,因此将数据包发往路由器R1。此时整个数据包源IP为IP1,目的IP为IP2。其源MAC为HA1,目标MAC为HA3。
  • 数据包到达路由器R1,被R1通过接口HA4发送给路由器R2。此时源、目的IP不变,源MAC变为HA4,目的MAC变为HA5。
  • 数据包到达路由器R2,R2发现目标设备在HA6接口管理的网段内,通过HA6接口将该包发到目标设备。此时源、目的IP依然不变,源MAC为HA6,目标MAC为HA2。

发现了吗?在本次跨网段的通信示例中,源IP和目标IP地址是不会发生变化的,原因在于IP地址作为“路标”,要指引数据路由方向;而MAC地址则是根据路由方向在两个直连设备之间实现通信,而每个设备接口都是有差异的,因此MAC地址在本次通信中是时刻变化的,用于在物理上真真实实将数据路由到指定下一跳位置。

另外,这里还得附注一下:

IP地址并不是全球唯一的,这里要注意,IP协议划分出了3类私有网段地址,这些地址在全球这么多网段中是肯定有重复的。

但是私有地址是局域网段内部使用的,无法直接连接公网。如果需要连接公网那么得走公网IP+NAT映射。更多详见IP地址体系、NAT地址转换


IP协议帧格式

认识一个协议,首先肯定得从协议报文格式入手。IP协议标准头部最少有20字节大小(大部分情况下都是20字节),这20字节携带了必要的通信讯息,如果还有剩余的字节,则为选项字段带一些额外通信参数。

字段 长度 含义
版本号 4 位 IPv4 = 4,IPv6 = 6
首部长度 4 位 以 4 字节为单位,最小 5(20 字节),最大 15(60 字节)
服务类型(TOS) 8 位 优先级 + 延迟/吞吐/可靠性标志(现多用于 DSCP)(看看就行,一般用不上)
总长度 16 位 首部 + 数据,最大 65535
标识 16 位 分片时用于重组,同一数据报的分片共享此 ID
标志 3 位 DF(不分片)、MF(还有分片)、保留位
分片偏移 13 位 本分片在原始数据报中的位置,以 8 字节为单位,同样用于重组
生存时间(TTL) 8 位 每经一跳减 1,为 0 时丢弃并回 ICMP 超时
协议 8 位 上层协议:1=ICMP,6=TCP,17=UDP
首部校验和 16 位 只校验首部,不校验数据
源 IP 32 位 发送方 IP
目标 IP 32 位 接收方 IP
选项 最多40字节 记录路由、时间戳、源路由等(很少用)

至于后面的数据部分,负责承载ICMP/UDP/TCP报文头部及其数据、以及应用层的数据。


IP分片与重组

上文我们提到了,IP统一了自网络层之上的内容。但是底层的数据链路层,其实现是各异的。一次跨网段的网络通信底层可能会经过多个不同的物理链路,而每个物理链路都维护有自己的MTU(最大传输单元)表示在该链路层中最大的传输帧长度。例如以太网MTU的典型值就是1500。

这就会导致出现一个问题:假如我们本地网段为以太网,MTU为1500。为了最大化提升效率,我们按照这个数字发包,结果网络包在中间某一跳时,进入了另一类型链路层,通道MTU < 1500了,这时候怎么办?

IP的分片与重组功能就是专门设计出来解决这个问题的——可以将数据包拆开分段传输过去,再由对端正确重组得到完整数据;上述情况中,这个时候中间路由器在传输时就可能会触发IP分片。

为什么说是可能?因为IP分片与重组是可选功能。必须满足以下条件才会触发分片和重组机制:

  • 接收方/发送方均开启IP分片重组功能,否则要不就一个发不出,要不就是收到不会重组。
  • 数据包IP头标志位必须设置可分片。若不允许分片则直接被丢弃。
  • 传输时IP数据报总长(IP头+数据) > 当前传输链路MTU。

上述示意图便是在中间路由器R1分片触发的场景,若允许分片,则进行切片与对端重组;若不允许则回复ICMP报文(类型3Code4)。

当然,要注意的是并不只有中间路由器会触发分片的情况,在源主机有时也会触发分片:比如Ethernet MTU=1500,我们从应用层向IP协议栈递交了一个大于1500字节的数据报,这个时候若我们开启了分片功能,那么在IP层就会主动将其分片发出。

这里讲讲分片重组的一些细节操作:

分片和重组都涉及到IP头部的几个关键字段:标识、标志、分片偏移、以及总长度。

我们以在Ethernet环境下一次性发送4000字节数据(此处演示源主机处分片),并且对端重组并正确接收4000字节数据为例:

  • 在发送数据包前,协议栈会检查总长度是否大于出口网络接口的MTU,如果总长度<MTU则直接发送;若总长度>MTU,则进行下一步。

  • 检查协议栈是否允许分片,若不允许分片则直接拒绝该次请求,并返回对应的错误给上层;若允许分片,则计算需要分为多少片。

  • 本示例要发送4000字节数据,每个分片最大承载的数据量为:1500 - 20(标准IP头部,无选项字节) = 1480字节。简单运算下可以得到总共需要分为三片:
    分片1:IP头20字节 + 1480字节数据;分片偏移0、MF = 1(后面还有分片)

    分片2:IP头20字节 + 1480字节数据;分片偏移185(注意,8字节为单位)、MF = 1(还有分片)
    分片3:IP头20字节 + 1040字节数据;分片偏移370、MF = 0(后面没有分片了)

  • 分片完毕,几个分片包的标识被打上相同ID表示都属于同一个大包,然后逐个以计算出的值填充每个分片的IP头后,依次发出。

这就是发送方IP分片的流程。这里有一个地方要注意:因为分片偏移以8字节为单位,所以除开最后一包数据以外,其它中间的包数据必须能够整除8字节。这通常由协议栈内部进行管理,我们无需干涉。例如将MTU设置为1499,1499 - 20 = 1479 是无法整除8的。这个时候协议栈内部会退到1472,然后剩下的数据丢给下一包。

接收方收到分片数据后:

  • 根据标识 + 源 IP + 目标 IP + 协议号将同一个大包的分片归为一类,并从中找出首片。
  • 而后根据分片偏移将所有分片进行排序。
  • 当所有分片收齐后(收到MF = 0的包),脱掉每个分片的IP头,然后按排序进行拼接。
  • 拼好后将完整数据报递交给上层。

我们在Linux中使用ICMP报文来实际看看该示例的情况:

1
2
3
4
5
6
#终端1
sudo ip link set eth0 mtu 1499 #设置MTU为1499.
ping -M dont -c 1 -s 4000 172.18.224.1 #Ping一次网关,数据大小为4000字节,允许分片

#终端2
sudo tshark -i eth0 icmp

运行后各终端情况如下:

1
2
3
4
5
6
7
8
9
10
11
#终端1
PING 172.18.224.1 (172.18.224.1) 4000(4028) bytes of data.
4008 bytes from 172.18.224.1: icmp_seq=1 ttl=128 time=0.359 ms

#终端2
172.18.228.235 → 172.18.224.1 IPv4 1506 Fragmented IP protocol (proto=ICMP 1, off=0, ID=4237)
172.18.228.235 → 172.18.224.1 IPv4 1506 Fragmented IP protocol (proto=ICMP 1, off=1472, ID=4237)
172.18.228.235 → 172.18.224.1 ICMP 1098 Echo (ping) request id=0x6940, seq=1/256, ttl=64
172.18.224.1 → 172.18.228.235 IPv4 1514 Fragmented IP protocol (proto=ICMP 1, off=0, ID=126b)
172.18.224.1 → 172.18.228.235 IPv4 1514 Fragmented IP protocol (proto=ICMP 1, off=1480, ID=126b)
172.18.224.1 → 172.18.228.235 ICMP 1082 Echo (ping) reply id=0x6940, seq=1/256, ttl=128 (request in 3)

可以看到,MTU=1499的情况下,我们4008字节(ICMP头部还要占8字节)数据被分为了三片,前两片数据负载均为1472(1479不可用,协议栈自动退回1472)。第三片总大小为1098,减去MAC14字节再减去20字节IP头部,最后IP数据负载为1064字节。1064 + 1472 * 2 = 4008字节,验算通过。

但是在实际网络环境中,其实都会尽量去避免使用分片功能。因为一段分片数据中,只要丢一个分片,那么所有分片都必须重传。而且将一段数据拆成多段发送,本身就加大了路由出错的风险,同时也增加设备负担。所以这也是为什么会有PMTUD技术,就是为了保证在正确路由到对端的整个环境中,我该发多大的包以至于不会在中间路径触发分片。


其它

关于选项字段

IP头部最多60字节,扣除掉20字节的固定标准头部,剩下40字节作为选项插入。选项字节部分是可变的,最大40字节,且必须满足4字节对齐(不满足将使用填充字节进行补齐)。

这40字节内部维护了一个类似于K-V(键值对应)的机制:也就是说IP选项的格式如下面所示

1
2
3
4
┌────────┬────────┬──────────────────┐
│Type │Length │ Value |
│1 字节 │1 字节 │ Length-2 字节 |
└────────┴────────┴──────────────────┘
  • Type:选项类型,比如源路由、记录路由路径等。
  • Length:选项总长度。
  • Value:选项的数据部分。

其中,Type的8位又被划分如下:

1
2
3
4
5
6
  0   1   2   3   4   5   6   7
┌───┬───┬───────────────────────┐
│ C │ C │ Number │
└───┴───┴───────────────────────┘
↑ ↑
复制标志 选项类别
  • 复制标志(Copied)占一位,表征是否将该选项字段复制到所有IP分片(若有分片的情况下)。0表示不复制,只有首片具有该选项;1表示复制,每个分片都有。
  • 类别占两位,0=控制;1=保留;2=调试和测量;3=保留。
  • 后面的Number编号就是具体的选项类别了(没用,了解一下)。

你比如:
严格源路由:Type = 137,类别是0(控制)

路径记录:Type = 7,类别是0(控制)

这里有两个特殊的单字节类型选项要注意:NOP、EOL。这两个作为选项但是没有常规控制头的Length和Value部分。NOP用于填补占位(前面说过选项要对齐到4字节,若未对齐就用NOP进行填补对齐)、EOL用于表征选项字段结束。

这里以一个路径记录的选项例子来看看实际的布局是什么样的:

路径记录其实就是traceroute,每一个中间路由器都将自己的IP写进Pointer指向的位置,最多记录9跳内容。但是当今互联网发展很多时候通信跳数大于9跳,所以这个功能基本不会使用。

IP选项需要额外解析,降低数据流通速度;而且存在一定的安全风险;同时功能也比较鸡肋。因此在当前的互联网环境中基本上不会被使用,很多协议栈默认设置是关闭IP选项字段功能的。这里只简单讲讲,不深入讨论。


关于TTL

TTL是网络数据包在网络环境中的存活时间。因为占1个字节,所以最大值为255。其典型值为64或255。需要注意的是这里的时间指的并不是我们常识中的分秒这一类时间,而是数据包在路由路径上经过的跳数。

数据包每经过一个中间路由器,TTL都会减少1,当TTL减到0时该包被丢弃。我们在Traceroute中依靠的原理就是TTL超时对端发回ICMP。

之所以要引入TTL,是为了防止失效数据包在网络环境中不断循环被转发。有了TTL,包最多经过255跳就会被丢弃,不会永久占用网络资源。


END

IP协议是网络层的核心,把数据包从源送到目标。不保证可靠、不保证顺序,这些交给上层。IP头的20字节里,每一个字段都有明确分工:版本、长度、分片、TTL、协议、校验和、源/目标 IP。分片是IP应对MTU差异的手段,但代价高,现代网络尽量用PMTUD技术来避免分片。IP选项是补充机制,几乎废弃。

作者

R6bandito

发布于

2026-10-06

更新于

2026-10-08

许可协议

评论

音乐
0:000:00