强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

TCP/UDP 网络协议教程 / 02-IP 协议基础

02 - IP 协议基础

2.1 IP 协议概述

IP(Internet Protocol)是网络层的核心协议,负责将数据包从源主机传输到目的主机。

关键特性:
• 无连接:不建立连接,直接发送
• 不可靠:不保证到达、不保证顺序
• 尽力而为:Best-effort delivery
• 路由:通过路由器逐跳转发

2.2 IPv4 头部结构

 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 Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
字段长度说明
Version4 bitIP 版本号(4 或 6)
IHL4 bit头部长度(单位:4字节)
Total Length16 bit数据包总长度(最大 65535)
TTL8 bit生存时间(每经过路由器减1)
Protocol8 bit上层协议(TCP=6, UDP=17)
Source Address32 bit源 IP 地址
Destination Address32 bit目的 IP 地址
# 解析 IP 头部示例
import struct

def parse_ip_header(data):
    """解析 IP 头部"""
    if len(data) < 20:
        return None
    
    # 解析前 20 字节
    fields = struct.unpack('!BBHHHBBHII', data[:20])
    
    version = fields[0] >> 4
    ihl = fields[0] & 0xF
    ttl = fields[5]
    protocol = fields[6]
    src_ip = struct.pack('!I', fields[8])
    dst_ip = struct.pack('!I', fields[9])
    
    import socket
    return {
        'version': version,
        'header_length': ihl * 4,
        'ttl': ttl,
        'protocol': protocol,  # 6=TCP, 17=UDP
        'src_ip': socket.inet_ntoa(src_ip),
        'dst_ip': socket.inet_ntoa(dst_ip)
    }

2.3 IPv4 地址

地址分类

类别范围默认掩码用途
A 类1.0.0.0 - 126.255.255.255/8大型网络
B 类128.0.0.0 - 191.255.255.255/16中型网络
C 类192.0.0.0 - 223.255.255.255/24小型网络
D 类224.0.0.0 - 239.255.255.255-多播
E 类240.0.0.0 - 255.255.255.255-保留

私有地址

类别地址范围CIDR
A 类10.0.0.0 - 10.255.255.25510.0.0.0/8
B 类172.16.0.0 - 172.31.255.255172.16.0.0/12
C 类192.168.0.0 - 192.168.255.255192.168.0.0/16

特殊地址

地址用途
0.0.0.0所有地址
127.0.0.1本地回环
255.255.255.255有限广播
169.254.x.x链路本地地址

2.4 子网划分

CIDR 表示法

IP地址/前缀长度
例如:192.168.1.0/24

前缀长度 24 表示前 24 位是网络部分
子网掩码:255.255.255.0
可用主机数:2^(32-24) - 2 = 254
import ipaddress

def subnet_info(network_str):
    """获取子网信息"""
    network = ipaddress.ip_network(network_str, strict=False)
    
    return {
        'network_address': str(network.network_address),
        'broadcast_address': str(network.broadcast_address),
        'netmask': str(network.netmask),
        'prefix_len': network.prefixlen,
        'total_hosts': network.num_addresses,
        'usable_hosts': network.num_addresses - 2 if network.prefixlen < 31 else network.num_addresses,
        'first_host': str(network.network_address + 1),
        'last_host': str(network.broadcast_address - 1)
    }

# 示例
print(subnet_info('192.168.1.0/24'))
# {'network_address': '192.168.1.0', 'broadcast_address': '192.168.1.255',
#  'netmask': '255.255.255.0', 'prefix_len': 24, 'total_hosts': 256,
#  'usable_hosts': 254, 'first_host': '192.168.1.1', 'last_host': '192.168.1.254'}

子网划分示例

原始网络:192.168.1.0/24(256 个地址)

划分为 4 个子网:
┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐
│  192.168.1.0/26 │ 192.168.1.64/26 │192.168.1.128/26 │192.168.1.192/26 │
│   64 个地址     │   64 个地址     │   64 个地址     │   64 个地址     │
│  .1 - .62       │  .65 - .126     │  .129 - .190    │  .193 - .254    │
└─────────────────┴─────────────────┴─────────────────┴─────────────────┘

2.5 IPv6 简介

IPv6 地址格式

128 位地址,冒号十六进制表示:

完整:2001:0db8:0000:0000:0000:0000:0000:0001
简化:2001:db8::1

规则:
1. 前导零可省略
2. 连续全零段可用 :: 替代(只能使用一次)

IPv4 vs IPv6

特性IPv4IPv6
地址长度32 位128 位
地址数量~43 亿~3.4×10^38
表示方法点分十进制冒号十六进制
头部大小20-60 字节40 字节(固定)
分片路由器和发送端仅发送端
校验和无(交给上层)
NAT广泛使用不需要

2.6 路由基础

路由表

# 查看路由表
$ ip route show
default via 192.168.1.1 dev eth0 
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100 
10.0.0.0/8 via 192.168.1.254 dev eth0
路由决策过程:

1. 提取目的 IP 地址
2. 与路由表逐条匹配(最长前缀匹配)
3. 找到匹配项 → 从指定接口转发
4. 无匹配项 → 使用默认路由(default gateway)
5. 无默认路由 → 丢弃并发送 ICMP 错误

路由类型

类型说明示例
直连路由直接连接的网络192.168.1.0/24 dev eth0
静态路由手动配置10.0.0.0/8 via 192.168.1.254
动态路由协议自动学习BGP、OSPF、RIP
默认路由兜底路由default via 192.168.1.1

2.7 IP 分片

分片原因

MTU (Maximum Transmission Unit):链路层最大传输单元

以太网 MTU = 1500 字节
IP 数据包最大 = 65535 字节

当 IP 包 > MTU 时,需要分片

分片字段

字段说明
Identification标识同一个数据包的所有分片
Flags.DFDon’t Fragment,不允许分片
Flags.MFMore Fragments,后面还有分片
Fragment Offset分片在原始数据包中的偏移(8字节为单位)
def analyze_fragments():
    """分片示例分析"""
    original_size = 4000  # 原始数据包大小
    mtu = 1500            # 链路 MTU
    ip_header = 20        # IP 头部大小
    max_data = mtu - ip_header  # 每片最大数据 = 1480
    
    fragments = []
    offset = 0
    remaining = original_size - ip_header  # 3980 字节数据
    
    while remaining > 0:
        frag_data = min(remaining, max_data)
        mf = 1 if remaining > max_data else 0
        
        fragments.append({
            'offset': offset,
            'data_size': frag_data,
            'MF': mf,
            'total_size': frag_data + ip_header
        })
        
        offset += frag_data
        remaining -= frag_data
    
    return fragments

for frag in analyze_fragments():
    print(f"分片: offset={frag['offset']:5d}, size={frag['data_size']:5d}, MF={frag['MF']}")
# 分片: offset=    0, size= 1480, MF=1
# 分片: offset= 1480, size= 1480, MF=1
# 分片: offset= 2960, size= 1020, MF=0

2.8 ICMP 协议

ICMP 是 IP 的辅助协议,用于错误报告和网络诊断。

类型代码说明工具
00Echo Replyping
30网络不可达-
31主机不可达-
33端口不可达-
80Echo Requestping
110TTL 超时traceroute
# ping 使用 ICMP Echo
$ ping -c 3 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=118 time=12.3 ms

# traceroute 使用 TTL 超时
$ traceroute 8.8.8.8
 1  192.168.1.1 (192.168.1.1)  1.234 ms
 2  10.0.0.1 (10.0.0.1)  5.678 ms
 ...

2.9 ARP 协议

ARP 将 IP 地址解析为 MAC 地址。

ARP 工作流程:

1. 主机 A 要发送数据给 192.168.1.2
2. A 检查 ARP 缓存表
3. 若无缓存,广播 ARP 请求:"谁是 192.168.1.2?"
4. 192.168.1.2 单播回复:"我是,MAC 是 xx:xx:xx:xx:xx:xx"
5. A 更新 ARP 缓存,发送数据
# 查看 ARP 缓存
$ arp -a
? (192.168.1.1) at 00:11:22:33:44:55 [ether] on eth0
? (192.168.1.2) at 66:77:88:99:aa:bb [ether] on eth0

2.10 注意事项

⚠️ MTU 问题:路径 MTU 发现(PMTUD)失败会导致连接问题,某些防火墙会丢弃 ICMP “需要分片"消息

⚠️ IP 地址耗尽:IPv4 地址已耗尽,NAT 和 IPv6 是解决方案

⚠️ 安全考虑:IP 欺骗(IP Spoofing)是常见的攻击手段,需要配合上层协议验证

2.11 扩展阅读


下一章03 - TCP 头部详解 - 深入理解 TCP 协议的每个字段