IP包结构

读万卷书,行万里路。

—— 佚名

掌握网络层基本工作原理后,是时候来认识网络层中的最重要的 IP 协议了。

IP互联网协议 ( internet protocol ) 的简称,是 TCP/IP 协议栈中的网络层协议。IP 协议在发展的过程中,衍生出 IPv4IPv6 两个不同版本。其中,历史版本 IPv4 目前仍广泛使用;后继版本 IPv6 世界各地正在积极部署。

IP 协议的通信单元是 IP ( packet ),同样分为 IPv4IPv6 两个版本,本节重点研究 IPv4 包结构。虽然我们对 IPv4 包结构仍一无所知,但经过网络层的学习,我们可以大致猜测一下:它应该分为头部和数据两大部分;其中头部应该包含源地址、目的地址以及数据类型等字段。

IPv4包

废话不多说,直接开门见山。一个 IPv4 包的结构是这样的:

我们猜得没错,IP 包也分为 头部 ( header ) 和 数据 ( data )两大部分,其中头部也可称为 首部 。虽然我们猜到了头部中的几个关键字段,头部却远比我们想象中的要复杂。

接下来,我们简要介绍一下 IP 头部各个字段。一开始看得一头雾水也没有关系,先有个大概印象即可,具体细节后续章节还会展开介绍。

版本

IP 头部第一个字段是 版本 ( version ),它占用 4 个比特,位于 IP 包的最前面,也就是第一个字节的高 4 位。采用 IP 协议通信的双方,使用的版本必须一致。对于 IPv4 ,该字段的值必须是 4

头部长度

由于 IP 头部可能包含数量不一的 可选选项 ,因此需要一个字段来记录头部大小,进而确定数据的偏移量,这就是 头部长度 ( internet header length , IHL )。

IHL 字段同样占用 4 个比特,它用来说明头部由多少个 32 位字组成。上述 IP 包结构图中,每一行就是一个 32 位字,由 32 个比特位构成,也就是 4 字节。因此,头部字节数可以这样计算:

$$IP包头部字节数 = 4 \times IHL$$

如果 IP 包不包含任何选项,头部大小为 532 位字(图中前 5 行),IHL 字段值则为 5 ( 二进制 0101 )。IHL 最大值为 15 ( 二进制 1111 ),因此 IP 头部最大为 60 字节,其中选项部分为 40 字节。

区分服务

区分服务 ( differentiated servicesDS )占 6 比特,一般情况下不使用。只有使用区分服务时,这个字段才起作用,例如:需要实时数据流的 VoIP

显式拥塞通告

显式拥塞通告( explicit congestion notificationECN ),允许在不丢包的同时通知对方网络拥塞的发生。

全长

全长 ( total length )字段占 16 位,它定义了 IP 包的总长度,包括头部和数据,单位为字节。这个字段最大值是 $2^{16}-1=65535$,因此理论上最大的 IP 可以达到 65535 字节。当 IP 包长度大于下层数据链路协议 MTU 时,IP 包就必须被 分片 (拆分成多个包)。

标识符

标识符 ( identification )字段占 16 比特,用来唯一标识一个包的所有分片。因为 IP 包不一定都能按时到达,在重组时需要知道分片所属的 IP 包,标识符字段就是一个 IP 包的 ID 。它一般由全局自增计数器生成,每发一个包,计数器就自动加一。

关于 IP 包分片技术的更多细节,将在后续章节中展开介绍。

标志

标识 ( flags )字段占 3 比特,包含几个用于控制和识别分片的标志位:

  • 0 位,保留,必须为 0
  • 1 位,禁止分片( don’t fragmentDF ),该位为 0 才允许分片;
  • 2 位,更多分片( more fragmentMF ),该位为 1 表示后面还有分片,为 0 表示已经是最后一个分片;

分片偏移

分片偏移 ( fragment offset )字段占 13 比特,表示一个分片相对于原始 IP 包开头的偏移量,以 8 字节为单位。

存活时间

存活时间 ( time to liveTTL )字段占 8 比特,避免 IP 包因陷入路由环路而永远存在。存活时间以秒为单位,但在具体实现中成了一个跳数计数器:IP 包每经过一个路由器,TTL 都被减一,直到 TTL 为零时则被丢弃。

协议

协议 ( protocol )字段占 8 比特,表示 IP 包数据类型。通常情况下,IP 包数据承载着一个上层协议报文,常见的有下面这些:

协议字段值 协议名 缩写
1 互联网控制消息协议 ICMP
2 互联网组管理协议 IGMP
6 传输控制协议 TCP
17 用户数据报协议 UDP
89 开发式最短路径优先 OSPF
132 流控制传输协议 SCTP

这也是一个非常典型的 复用/分用 字段:不同的上层协议报文,都可以利用 IP 协议提供的能力,互联网主机间进行传输。

头部校验和

头部校验和 ( header checksum )字段占 16 比特,与以太网帧校验和字段类似,用于对报文进行查错。

注意到,该字段只对 IP 头部查错,而不关心数据部分。这是因为 IP 包数据一般用来承载上层协议报文,例如 UDPTCP ,而它们的报文都有自己的校验和字段。

每一跳路由收到 IP 包后,都要重新计算头部校验和并与该字段对比,不一致则将其丢弃。路由转发 IP 包前,也要重新计算并填写该字段,因为头部中的一些字段可能发生变化——每次转发,TTL 字段都要减一。

源地址

源地址 ( source address ),占用 32 比特,也就是 4 字节,表示 IP 包发送方的地址。

IP 地址由 32 位组成,理论上可以表示多达 $2^{32} = 4294967296$ (约等于 40 亿)台主机。实际上,IP 地址按用途分成几类,能用于公网通信的 IP 地址没有这么多。

  • 公网地址
  • 内网地址
  • 本地地址
  • 多播地址
  • 广播地址

关于 IP 地址结构和类别,后续有独立章节专门展开介绍。

目的地址

目的地址 ( destination address ),格式与源地址相同,表示 IP 包接收方的地址。

选项

这是 IP 包的可选字段,并不常用,后续用到时再结合具体场景来讲解。

小菜学网络】系列文章首发于公众号【小菜学编程】,敬请关注:

【小菜学网络】系列文章首发于公众号【小菜学编程】,敬请关注: