IP分片是指IP协议将一个大的数据包分割成多个较小的包进行传输的过程。
IP分片的主要作用是:
- 适应不同网络的MTU:不同的网络可能有不同的最大传输单元(MTU),通过 IP分片可以在网络层对包进行分割,使其符合各个网络的MTU限制。
- 更好的利用网络带宽:一个大的数据包可能会阻塞其他包的发送,通过分片可以提高网络利用效率。
- 较小的包丢失概率:一个大包丢失的概率较一个小包丢失的概率高,分片可以减少数据丢失。
IP分片的过程如下:
- 确定每个分片的长度,不能超过目的主机网络的MTU。
- 第一片包含IP头部,且分片偏移为0。其余分片使用自己的IP头部,分片偏移非0。
- 在重新组装时,接收方利用每个分片的源IP地址、目标IP地址和标识字段将它们重新组装成完整的IP数据报。
- 如果某个分片丢失,重传请求只需请求丢失的分片。
代码示例:
python
from random import randint
# IP分片
def fragmentation(ip_header, data):
mtu = 576 # MTU
total_length = ip_header.total_length
offset = 0
ip_headers = [] # 分片IP头部
fragments = [] # 分片
while total_length > 0:
length = min(total_length, mtu) # 分片长度
# 构造分片
frag = data[offset:offset+length]
fragments.append(frag)
# 构造分片IP头部
ip_header.total_length = length
ip_header.fragment_offset = offset // 8
ip_headers.append(ip_header.pack())
offset += length
total_length -= length
return ip_headers, fragments
# 发送方
ip_header = IPHeader('192.168.1.1', '192.168.1.2', 6, 2000)
ip_headers, fragments = fragmentation(ip_header, data)
for ip_header, frag in zip(ip_headers, fragments):
datagram = ip_header + frag
sock.sendto(datagram, ('192.168.1.2', 80))
# 接收方
fragments = []
while True:
msg, addr = sock.recvfrom(mtu + 20) # 带IP头部的分片
ip_header = IPHeader(msg[:20])
# 使用标识字段判断是否属于同一数据报
if ip_header.identification == id:
fragments.append(msg[20:]) # 添加分片数据
else:
# 重新组装并处理上一数据报的分片
whole_packet = b''.join(fragments)
handle_packet(whole_packet)
# 开始接收新数据报的分片
id = ip_header.identification
fragments = [msg[20:]]