IP分片

链路层具有最大传输单元MTU这个特性,它限制了数据帧的最大长度,不同的网络类型都有一个上限值。以太网的MTU是1500,你可以用 netstat -i 命令查看这个值。如果IP层有数据包要传,而且数据包的长度超过了MTU,那么IP层就要对数据包进行分片(fragmentation)操作,使每一片的长度都小于或等于MTU。我们假设要传输一个UDP数据包,以太网的MTU为1500字节,一般IP首部为20字节,UDP首部为8字节,数据的净荷(payload)部分预留是1500-20-8=1472字节。如果数据部分大于1472字节,就会出现分片现象。

IP首部包含了分片和重组所需的信息:

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       Identification     |R|DF|MF|   Fragment Offset   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|<-------------16-------------->|<--3-->|<---------13---------->|

Identification:发送端发送的IP数据包标识字段都是一个唯一值,该值在分片时被复制到每个片中。
R:保留未用。
DF:Don't Fragment,“不分片”位,如果将这一比特置1 ,IP层将不对数据报进行分片。
MF:More Fragment,“更多的片”,除了最后一片外,其他每个组成数据报的片都要把该比特置1。
Fragment Offset:该片偏移原始数据包开始处的位置。偏移的字节数是该值乘以8。

另外,当数据报被分片后,每个片的总长度值要改为该片的长度值。


我们都知道,在以太网中,如果源主机向目标主机发送的数据包大于网关MTU,则该数据包在传输过程中会被IP协议分片传输,具体的分片过程是怎样的呢?我们通过协议分析软件抓包来进行详细的查看(抓包软件使用科来网络分析系统)。
因为以太网默认的MTU值为1500Byte,所以,为了达到分片的效果,我们应该传输大于1500Byte字节的数据包,才能使该数据包分段传输。
我们从本机(192.168.6.11)发送一个2000字节的数据包到局域网的另一台主机(192.168.0.208)为例,在传输的过程中,开启软件抓包,就能够查看到详细的分片结果。
我们以ping为例,在Windows命令提示符下输入:ping 192.168.0.208 –l 2000
通过科来网络分析系统抓包,我们看到,该数据包被分片了,由于我们重复Ping了4次,所以,抓到了4次同样的请求与回显的数据包。如下图:

         查看详细的数据包解码(见下图):
   

  
分析:因为ping的长度是2000字节,大于了MTU的值,所以会分片发送,如上图。捕获的这个数据包总长度为1500字节,更多分段位置1,表示还有数据分段。s,偏移量为0,需要注意的是IP头部的总长度字段值(这里是1500字节)并不全是数据的净载荷长度,这里还包括了IP以及ICMP的头部长度,分别是20字节和8字节。
另外,IP协议的头部总长度并不一定就是MTU值1500字节,这个值与网络环境、操作系统等因素有关。
    下图是第一个分片包。


 
分析:IP字段的标识0x787F,与第一个包相同,说明这是同一个数据包,只是被分片了。
    偏移量为185,表示相对第一个包的位置,以便接收主机根据偏移量进行数据重组。
    需要注意的是此处分片包并没有ICMP字段,接收主机会可以根据偏移重组成完整的ICMP数据包。
最后,我们来计算一下该数据包的长度:第一个数据包的总长度为1500字节,减去IP头部长度20字节,减去ICMP头部长度8字节,即1500-20-8=1472字节;第二个数据包的总长度为548字节,减去IP头部长度20字节,即548-20=528字节,两个数据包的净载荷1472+528=2000,正好是我们发送的数据长度。


本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/aaa6695798/archive/2009/12/13/4980494.aspx

### IP分片的概念与实现 在网络通信中,数据可能需要通过具有不同最大传输单元(MTU)的网络链路进行传输。如果某个数据的大小超过了特定链路上允许的最大值,则路由器会对其进行分割成较小的部分以便于传递,这一过程称为IP分片。 #### 数据分片的原因 当IPv4数据报超过路径上任何链路层协议所支持的数据帧长度时,就需要对该数据报进行分片处理[^1]。这种机制确保即使存在较大尺寸的数据也能顺利穿越那些仅能承载较短消息片段的媒介环境。 #### 分片字段详解 为了能够重新组装被拆散的数据块,在每一个IP头部都含了几个专门用于描述如何切割以及怎样拼接回原始状态的关键参数: - **标志位(Flags)**: 这是一个三位二进制数列其中最后两位用来指示是否可以进一步细分当前部分(`MF` More Fragments),以及此份是不是整个序列里的首个成员。 - `DF (Don't Fragment)` 如果设置则不允许再做额外划分;否则可能会触发ICMP错误通知发送端调整策略或者丢弃无法满足条件的信息单位。 - **偏移量(Fragment Offset)** : 表明该碎片相对于原封不动的整体起始位置的具体字节数目差额除以八后的数值结果。它帮助接收方理解每一块应该放在哪里来恢复最初的连续流形式。 - **识别号(Identification Field)** :由源主机分配给每个向外发出的新连接请求唯一的ID编号,使得目标设备可以根据相同的标识符收集属于同一个事务的所有零星部件并按序排列组合起来还原初始状况。 #### 实现流程概述 1. 当一个过大的数据到达接口准备转发出去之前,出口网关检查即将使用的下一跳链接所能接受的最大载荷容量; 2. 若发现现有规模超出规定界限而未设定禁止分裂标记,则启动相应算法操作将其分解为若干适配规格的小型组件; 3. 对每一项新产生的个体赋予恰当更新过的首部信息,特别是上述提及到的各项控制属性; 4. 将这些独立却又相互关联着彼此间关系线索的实体逐一投递给下游节点继续旅程直至抵达最终目的地为止。 值得注意的是,在实际应用过程中由于种种原因可能导致某些组成部分丢失从而影响整体效果呈现质量下降等问题发生因此现代通讯体系更倾向于采用其他替代方案比如MSS协商机制提前规避此类风险情况出现。 ```python def fragment_packet(packet, mtu): fragments = [] while len(packet.payload) > mtu: fragment_payload = packet.payload[:mtu] new_fragment = Packet( identification=packet.identification, flags='MF' if len(packet.payload[mtu:]) > 0 else 'none', offset=len(fragments)*int(mtu/8), payload=fragment_payload ) fragments.append(new_fragment) packet.payload = packet.payload[mtu:] # Add last fragment without MF flag final_fragment = Packet( identification=packet.identification, flags='none', offset=len(fragments)*int(mtu/8), payload=packet.payload ) fragments.append(final_fragment) return fragments ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值