
🔥个人主页:Cx330🌸
❄️个人专栏:《C语言》《LeetCode刷题集》《数据结构-初阶》《C++知识分享》
《优选算法指南-必刷经典100题》《Linux操作系统》:从入门到入魔
《Git深度解析》:版本管理实战全解 《Qt 极境架构》MySQL 核心技术与实战
🌟心向往之行必能
🎥Cx330🌸的简介:

目录
[一. 网段划分:IP 地址的 "身份证" 与 "家庭住址"](#一. 网段划分:IP 地址的 "身份证" 与 "家庭住址")
[1.1 IP 地址的本质:网络号 + 主机号](#1.1 IP 地址的本质:网络号 + 主机号)
[1.2 早期方案:分类划分法(A/B/C/D/E 类)](#1.2 早期方案:分类划分法(A/B/C/D/E 类))
[1.3 进化版:CIDR 无类别域间路由与子网掩码](#1.3 进化版:CIDR 无类别域间路由与子网掩码)
[1.4 懒人福音:DHCP 自动 IP 分配](#1.4 懒人福音:DHCP 自动 IP 分配)
[二. 为什么要划分子网?从 "大海捞针" 到 "精准定位"](#二. 为什么要划分子网?从 "大海捞针" 到 "精准定位")
[三. IP 协议的核心补充知识](#三. IP 协议的核心补充知识)
[3.1 那些特殊的 IP 地址](#3.1 那些特殊的 IP 地址)
[3.2 IPv4 地址危机与解决方案](#3.2 IPv4 地址危机与解决方案)
[3.3 私有 IP 与公网 IP:内网与外网的边界](#3.3 私有 IP 与公网 IP:内网与外网的边界)
[3.4 NAT 技术:拯救 IPv4 的 "幕后英雄"](#3.4 NAT 技术:拯救 IPv4 的 "幕后英雄")
[四. IP 协议头格式与源码解读](#四. IP 协议头格式与源码解读)
[4.1 IPv4 协议头完整解析](#4.1 IPv4 协议头完整解析)
[4.2 Linux 内核中的 iphdr 结构体详解](#4.2 Linux 内核中的 iphdr 结构体详解)
[五. 路由:数据包的 "导航系统"](#五. 路由:数据包的 "导航系统")
[1. 本地网段判断与 ARP](#1. 本地网段判断与 ARP)
[2. 路由表查找(最长前缀匹配原则)](#2. 路由表查找(最长前缀匹配原则))
[3. 数据包逐跳转发(Hop-by-Hop)](#3. 数据包逐跳转发(Hop-by-Hop))
前言:
在互联网的庞大世界中,每天有数以千亿计的数据包在不同的设备之间穿梭。如果我们把互联网比作庞大的邮政物流网络,那么 IP 协议(Internet Protocol) 就是整个网络的基石,它为每一个连接进来的设备颁发"地址",并制定了数据包投递的基本法则。
无论你是正在学习计算机网络的学生,还是希望深入研究网络排错与高性能网络编程的开发者,深刻理解 IP 协议及其底层机制都是不可或缺的基本功。本文将严格按照网段划分、子网掩码、特殊地址、IPv4 协议头以及 Linux 内核源码等维度,全方位带你拆解 IP 协议的核心秘密。
一. 网段划分:IP 地址的 "身份证" 与 "家庭住址"
1.1 IP 地址的本质:网络号 + 主机号
在 IPv4 协议中,一个 IP 地址由 32 位二进制数(4 字节) 组成。为了方便人类阅读,通常采用 点分十进制(Dotted Decimal Notation) 表示,例如 192.168.1.1。
从逻辑上看,一个 IP 地址被划分为两个核心部分:
-
网络号(Network ID):标识该设备属于哪一个独立的物理或逻辑网络(类似于"省/市/小区")。
-
主机号(Host ID):标识该设备在其所在的网络内部是哪一台具体的主机(类似于"门牌号")。
公式:网络号 + 主机号 = 子网(局域网)
例如192.168.128.10/24中,/24表示前 24 位是网络号(192.168.128),后 8 位是主机号(10)。
+-----------------------------------+-----------------------------------+
| 网络号 (Network ID) | 主机号 (Host ID) |
+-----------------------------------+-----------------------------------+
|<------------------------------ 32 Bits ------------------------------->|
当源主机向目标主机发送数据包时,路由器首先根据目标 IP 的网络号 进行跨网路由,到达目标网络后,再根据主机号将数据精确送达对应的主机。
1.2 早期方案:分类划分法(A/B/C/D/E 类)
在互联网发展初期,RFC 791 提出了分类 IP 地址(Classful Addressing) 方案,将 32 位的地址空间划分为 5 大类:
| 类别 | 首位固定比特 | 网络号长度 | 主机号长度 | 网络号范围 | 默认子网掩码 | 单网络最大主机数 | 主要用途 |
|---|---|---|---|---|---|---|---|
| A 类 | 0 |
8 bits | 24 bits | 1.0.0.0 ~ 126.0.0.0 | 255.0.0.0 | 2^24-2 = 16,777,214 | 超大型网络 |
| B 类 | 10 |
16 bits | 16 bits | 128.0.0.0 ~ 191.255.0.0 | 255.255.0.0 | 2^16-2 = 65,534 | 中型网络/企业 |
| C 类 | 110 |
24 bits | 8 bits | 192.0.0.0 ~ 223.255.255.0 | 255.255.255.0 | 2^8-2 = 254 | 小型局域网 |
| D 类 | 1110 |
- | - | 224.0.0.0 ~ 239.255.255.255 | - | - | 组播(Multicast) |
| E 类 | 1111 |
- | - | 240.0.0.0 ~ 255.255.255.255 | - | - | 保留/科研测试 |
传统分类划分法的缺陷: 颗粒度过于粗糙。申请一个 B 类网络拥有 6.5 万个地址,对于中小型企业来说根本用不完;而申请 C 类网络仅有 254 个可用地址,又极易不够用。这导致了早期 IPv4 地址空间的严重浪费。
1.3 进化版:CIDR 无类别域间路由与子网掩码
为了彻底解决分类 IP 地址的浪费问题,1993 年推出了 CIDR(Classless Inter-Domain Routing,无类别域间路由)。
CIDR 放弃了固定的 A/B/C 类界限,引入了 子网掩码(Subnet Mask) 。 子网掩码是一个 32 位的二进制数,其高位连续的 1 表示网络号,低位连续的 0 表示主机号。
例如,对于 CIDR 记法 192.168.1.100/24:
-
/24 表示前 24 位为网络号(子网掩码为 255.255.255.0)。
-
计算网络地址的过程是:将 IP 地址与子网掩码进行按位与(AND)运算。

二进制计算示例:
IP 地址: 192.168.00000001.01100100 (192.168.1.100)
子网掩码: 255.255.11111111.00000000 (255.255.255.0)
----------------------------------------------------
网络地址: 192.168.00000001.00000000 (192.168.1.0)
通过 CIDR,网络管理者可以根据需要任意划分网段大小(例如 /27 可以提供2^32-27-2 = 30 个可用地址),大大提升了 IP 地址的利用效率。



1.4 懒人福音:DHCP 自动 IP 分配
手动配置 IP 地址、子网掩码、网关和 DNS 既繁琐又容易发生地址冲突。DHCP(Dynamic Host Configuration Protocol,动态主机配置协议) 应运而生。
DHCP 运行在 UDP 协议之上(服务端端口 67,客户端端口 68),采用 DORA 交互模型 自动给新接入的主机分配 IP 地址:
Client DHCP Server
| |
| -------- 1. DHCP Discover (广播 255.255.255.255) -> |
| |
| <------- 2. DHCP Offer (单播/广播 提供 IP 建议) --- |
| |
| -------- 3. DHCP Request (广播 请求租用 IP) -------> |
| |
| <------- 4. DHCP ACK (单播/广播 确认配置) -------- |
| |
-
Discover(发现):客户端刚入网,不知道任何信息,发出广播包询问"网络中有 DHCP 协议服务器吗?"。
-
Offer(提供):DHCP 服务器收到后,从预留地址池挑选一个未使用 IP,发出回应。
-
Request(请求):客户端选择其中一个 Offer,发广播包确认"我打算租用这个 IP"。
-
ACK(确认):服务器确认租期(Lease Time)及配置(子网掩码、网关、DNS 等),完成分配。
二. 为什么要划分子网?从 "大海捞针" 到 "精准定位"
我们用一个 "归还钱包" 的故事来理解子网划分的意义:
- 学校分为多个学院,学号 = 院号(网络号)+ 个人编号(主机号)
- 张三捡到李四的钱包,只看到学号06321
- 张三首先判断院号06不是自己学院的,直接找本院学生会主席(路由器)
- 主席将消息转发到校群(公网),找到机械学院主席(目标网段路由器)
- 机械学院主席在本院群(目标子网)找到李四
核心结论 :划分子网的本质是提高路由查找效率。路由的本质是 "排除法",通过网络号可以一次性排除整个网段的设备,而不是逐个遍历所有主机。如果没有子网划分,全球几十亿设备在同一个网络中,路由查找将变成 "大海捞针",网络根本无法正常运行。
三. IP 协议的核心补充知识
3.1 那些特殊的 IP 地址
在 IPv4 地址空间中,有几类特殊的 IP 地址具有特殊用途,不能作为普通主机地址分配:
-
0.0.0.0/8:代表"任意地址"或"本网络中的本主机"。在路由表中常用作默认路由(Default Route) 的目标网络。
-
127.0.0.0/8(环回地址 Loopback) :最典型的是 127.0.0.1。发往该地址的数据包不会经过物理网卡传出,而是直接由内核环回驱动(lo)接收,常用于本机服务测试与进程间通信。
-
广播地址:
-
受限广播地址 :255.255.255.255,代表当前局域网内的所有主机(路由器不转发此广播)。
-
直接广播地址 :主机号全为
1的地址(例如 192.168.1.255/24),发往特定网段的所有主机。
-
-
网络地址 :主机号全为 0的地址(例如 192.168.1.0/24),代表该网段本身。
-
APIPA 地址(169.254.0.0/16):自动私有 IP 地址。当主机开启了 DHCP 却未能成功联系上 DHCP 服务器时,系统会自动从该网段随机挑选一个 IP 进行临时局域网通信。
3.2 IPv4 地址危机与解决方案
IPv4 总共只能提供 2^32 = 42.9 亿个地址。随着移动互联网和物联网的爆发,IPv4 地址早在 2011 年(IANA 正式耗尽)就已经告罄。
为了解决危机,网络工程界提出了"治标"与"治本"两类方案:
-
短期/过渡方案(治标) :CIDR(减少浪费)、私有 IP + NAT 技术(极大提升单个公网 IP 的容纳能力)。
-
终极方案(治本) :全面升级至 IPv6。IPv6 使用 128 位地址空间,可提供 2^128 = 3.4 * 10^38 个地址,号称能为地球上的"每一粒沙子都分配一个 IP"。
3.3 私有 IP 与公网 IP:内网与外网的边界
根据 RFC 1918 规范,IPv4 预留了三块地址空间专门用于局域网内部通信,即 私有 IP(Private IP):
| Class | 私有 IP 地址范围 | 网段段数/大小 |
|---|---|---|
| A 类 | 10.0.0.0 ~ 10.255.255.255 | 10.0.0.0/8 (1 个 A 类) |
| B 类 | 172.16.0.0 ~ 172.31.255.255 | 172.16.0.0/12 (16 个连续 B 类) |
| C 类 | 192.168.0.0 ~ 192.168.255.255 | 192.168.0.0/16 (256 个连续 C 类) |
-
私有 IP :可以在全球不同的企业或家庭局域网内部重复使用 ,但在公网路由器上是不可路由的(公网路由器会直接丢弃源或目的为私有 IP 的数据包)。
-
公网 IP :由运营商(ISP)统一分配,在全球范围内具有唯一性,可以直接在互联网上传输。
3.4 NAT 技术:拯救 IPv4 的 "幕后英雄"
NAT(Network Address Translation,网络地址转换) 是使得现代多台设备共享一个公网 IP 访问互联网的幕后功臣。最常用的是 NAPT(网络地址端口转换 / Port Address Translation)。
-
路由器有两个 IP:LAN 口 IP (内网网关,如192.168.1.1)和WAN 口 IP(运营商分配的公网 IP)
-
内网设备访问外网时,路由器会将数据包的源 IP替换为自己的 WAN 口 IP
-
响应数据包返回时,路由器再将目的 IP替换为对应的内网设备 IP
-
多级 NAT:家用路由器→运营商路由器→公网,逐级替换 IP 地址
[ 内网主机 ] [ 路由器 (NAT) ] [ 公网服务器 ]
192.168.1.100:50001 公网 IP: 1.2.3.4 93.184.216.34:80
| | |
| ------ 1. 发送请求数据包 ------------------> | |
| Src: 192.168.1.100:50001 | |
| Dst: 93.184.216.34:80 | |
| | -- 2. 转换源 IP 与端口并发送 --------------> |
| | Src: 1.2.3.4:61001 |
| | Dst: 93.184.216.34:80 |
| | |
| | <-- 3. 响应数据包 ----------------------- |
| | Src: 93.184.216.34:80 |
| | Dst: 1.2.3.4:61001 |
| <----- 4. 根据 NAT 表项映射还原并转发 -------- | |
| Src: 93.184.216.34:80 | |
| Dst: 192.168.1.100:50001 | |
NAT 映射表结构示例如下:
| 内网 IP:端口 | 外网映射 IP:端口 | 目标 IP:端口 |
|---|---|---|
| 192.168.1.100:50001 | 1.2.3.4:61001 | 93.184.216.34:80 |
| 192.168.1.101:50001 | 1.2.3.4:61002 | 93.184.216.34:80 |
NAT 极大地延缓了 IPv4 地址枯竭的速度,但也破坏了 IP 的"端到端透明通信"原则,导致内网设备主动提供公网服务时需要进行"端口映射(Port Forwarding)"。
四. IP 协议头格式与源码解读
4.1 IPv4 协议头完整解析
IPv4 报文由 IP 报头(Header) 和 数据载荷(Payload) 组成。一个不带选项的标准 IPv4 报头长度固定为 20 字节。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options (if IHL > 5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
各字段功能详解:
-
版本号(Version, 4 bits) :对 IPv4 而言值为
4。 -
首部长度(IHL - Internet Header Length, 4 bits) :以 4 字节(32 位 Word)为单位。最小值为 5(即 5 * 4 = 20 字节),最大值为 15(即 60 字节)。
-
服务类型(ToS / DiffServ, 8 bits):用于 QoS 服务质量控制,标记数据包的优先级与延迟要求。
-
总长度(Total Length, 16 bits):整个 IP 数据包(首部 + 数据)的总字节数。理论最大值为 2^16-1 = 65,35 字节。
-
标识(Identification, 16 bits):用于分片重组。属于同一个原始数据包的分片拥有相同的标识值。
-
标志位(Flags, 3 bits):
-
Bit 0: 保留,必须为 0。
-
Bit 1: DF (Don't Fragment):置 1 表示禁止路由器分片。
-
Bit 2: MF (More Fragments):置 1 表示后面还有分片,置 0 表示最后一个分片。
-
-
片偏移(Fragment Offset, 13 bits) :指示当前分片相对于原始数据载荷起始位置的偏移量,单位为 8 字节。
-
生存时间(TTL - Time to Live, 8 bits):数据包能经过的最大路由器跳数(Hop)。每经过一个路由器该值减 1,减至 0 时被丢弃,并向源端发送 ICMP Time Exceeded 报文,防止路由环路死循环。
-
上层协议(Protocol, 8 bits) :标识 IP 载荷中传输的上层协议(例如:ICMP 为
1,TCP 为6,UDP 为17)。 -
首部校验和(Header Checksum, 16 bits):仅校验 IP 报头自身的完整性(数据部分由传输层校验)。
-
源 IP / 目的 IP(Source/Destination IP Address, 32 bits):数据包的发送方与接收方地址。
4.2 Linux 内核中的 iphdr 结构体详解
在 Linux 内核网络协议栈源码(如 <linux/ip.h>)中,IPv4 报头被直接定义为 struct iphdr:
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4, /* 首部长度 (Internet Header Length) */
version:4; /* 版本号 (Version) */
#elif defined(__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos; /* 服务类型 (Type of Service) */
__be16 tot_len; /* 总长度 (Total Length) */
__be16 id; /* 标识 (Identification) */
__be16 frag_off; /* 标志位 (Flags) + 片偏移 (Fragment Offset) */
__u8 ttl; /* 生存时间 (Time to Live) */
__u8 protocol; /* 上层协议 (Protocol) */
__sum16 check; /* 首部校验和 (Header Checksum) */
__be32 saddr; /* 源地址 (Source Address) */
__be32 daddr; /* 目的地址 (Destination Address) */
/* The options start here. */
};
源码中的技术细节解读:
-
位域与字节序(Bitfield & Endianness) :C 语言结构体使用位域
:4划分高 4 位与低 4 位。由于网络字节序是大端模式,而主机可能为小端模式,内核必须根据 __LITTLE_ENDIAN_BITFIELD或 __BIG_ENDIAN_BITFIELD来颠倒 ihl与 version的定义顺序。 -
__be16与__be32类型 :前缀__be表示 Big Endian(大端位)。多字节字段在进入网络传输前必须使用 htons() / htonl() 转换位网络字节序,从网络接收后需使用 ntohs() / ntohl() 转为主机字节序。 -
frag_off组合字段 :高 3 位存储 Flags(如 IP_DF、IP_MF),低 13 位存储偏移量。内核解析时常使用掩码进行提取:- flags = ntohs(iph->frag_off) & IP_OFFSET;
五. 路由:数据包的 "导航系统"
当一个 IP 数据包构造完毕后,它是如何一步步穿越万水千山到达终点的?这就需要依赖路由机制。
[ 发送端主机 ] ──> [ 路由器 A ] ──> [ 路由器 B ] ──> [ 目标主机 ]
1. 本地网段判断与 ARP
发送端首先将目标 IP 与自身的子网掩码 进行 AND运算:
-
若属于同一子网 :直接通过 ARP 协议 查询目标 IP 的 MAC 地址,在二层(以太网)直接投递。
-
若属于异地网段 :必须将数据包发送给默认网关(Default Gateway) 处理。
2. 路由表查找(最长前缀匹配原则)
路由器收到数据包后,剥离二层帧头,取出 IP 头的目标地址,并检索路由表(Routing Table)。
典型的 Linux 路由表结构(通过 ip route show 输出):
default via 192.168.1.1 dev eth0 proto dhcp metric 100
10.0.0.0/8 via 10.1.1.1 dev eth1
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100
当多条路由规则都能匹配目标 IP 时,路由器遵循 最长前缀匹配(Longest Prefix Match) 原则------优先选择子网掩码最长(网络号最精确)的那条路由。
3. 数据包逐跳转发(Hop-by-Hop)
-
路由器将 IP 报头中的 TTL 减 1。若 TTL 减至 0,则直接丢弃包并向源地址发送 ICMP 错误响应。
-
重新计算 IP 首部的 CheckSum。
-
查找下一跳(Next Hop)的 MAC 地址,重新封装二层以太网帧(源 MAC 改为当前路由器接口 MAC,目的 MAC 改为下一跳 MAC)。
-
将数据包从对应的物理网口发送出去。
在整个路由转发过程中,IP 报头中的源 IP 和目的 IP 始终保持不变 (除非经过 NAT 转换),而二层的源 MAC 和目的 MAC 则在每一跳之间不断重写。
结尾:
IP 协议作为 TCP/IP 协议栈中网络层(Layer 3)的核心,通过逻辑地址划分(CIDR/子网掩码) 解决了海量设备的定位问题,通过 NAT 技术 极大延长了 IPv4 的使用寿命,并通过无连接、尽力而为(Best-Effort) 的简洁设计,实现了极高的转发效率。
从应用层的 HTTP/RPC 请求,到传输层的 TCP 三次握手,所有数据的骨架最终都需要封装在 IP 报文中穿梭于路由器之间。深刻理解 IP 协议的结构与路由逻辑,不仅能让我们对网络排错(如 ping、traceroute、tcpdump)更加游刃有余,也为进一步探索 Linux 内核网络栈及高性能网络开发奠定了坚实的基础。