IP分片

本文介绍了IP分片的原因,主要是由于数据链路层的MTU限制。IP分片发生在IP层,由源主机和路由器执行。为了避免IP分片带来的传输效率问题,网络编程中通常限制UDP包大小不超过1472字节,而TCP层在建立连接时协商MSS以防止分片。IP分片的重组在目的主机的IP层完成,涉及分片标识、标志位和偏移量。重组过程需要高效管理,包括快速定位、插入、判断完整性和超时机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

》引入IP分片的原因:

          在数据链路层,以太网和802.3对数据帧的长度都有一个限制,最大长度为1500和1492个字节,这个特性称为MTU。当IP层的数据报要传向数据链路层,并且比MTU大,则这时就需要对数据报进行分片,把数据报分成若干片,每一片都小于MTU。


》IP层如何对数据报进行分片:

          IP分片发生在IP层,不仅源端主机会进行分片,源端网络也会分片。不同网络的MTU不同,当目标网络的MTU小于源网络,路由器就会对IP数据报进行分片。分片数据的重组发生在目的端的IP层。

         在IP首部有4个字节是用于分片的,如下图所示。前16位是IP数据报的标识,同一个数据报的各个分片的标识是一样的,目的端会根据这个标识来判断IP分片是否属于同一个IP数据报。中间3位是标志位,其中有1位用来表示是否有更多的分片,如果是最后一个分片,该标志位为0,否则为1。后面13位表示分片在原始数据的偏移,这里的原始数据是IP层收到的传输的TCPUDP数据,不包含IP首部。



         需要注意的,在分片的数据中,传输层的首部只会出现在第一个分片中,如下图所示。因为传输层的数据格式对IP层是透明的,传输层的首部只有在传输层才会有它的作用,IP层不知道也不需要保证在每个分片中都有传输层首部。所以,在网络上传输的数据包是有可能没有传输层首部的。


》三位标志:

      第一位是为以后用准备;第二位表示是否分片,若为1则不进行分片,如果这个数据报不能通过网络转发,则丢弃,若为0,则在需要时对数据报进行分片;第三位表示“更多分片”,若为1,则表示还有分片,若为0则为最后一个分片。


》如何避免IP分片?

       在网络编程中,我们要避免IP分片,原因是IP层是没有超时重传机制的,如果IP层对一个数据包进行了分片出现差错,少传之类的,则需要从TCP层重新进行传输,需要将整个数据包,所有分片都进行重传,这个代价特别大,由此可见,IP分片会大大的降低传输层传输数据的成功率,所以我们就要避免IP分片。

       对于UDP包,我们需要在应用层限制每个包的大小,一般不要超过1472个字节,即1500-UDP头部(8)-IP头部(20)。

       但是对于TCP包,应用层则没有必要考虑包大小的问题,因为传输层已经做了这个事情。在建立三次握手的过程中,连接双方会相互通知MSS(Maximum Segment Size,最大报文段长度),MSS一般是MTU-IP首部(20)-TCP首部(20),每次发送的TCP数据都不会超过超过双方的MSS的最小值,所以就保证了IP数据报不会超过MTU,避免了IP分片。

》IP分片重组:

        IP分片的重组发生在目的主机的IP层,接收主机在第一个分片到达时会分配一个存储缓冲区,与此同时,主机还会启动一个计数器,接下来到达的分片会根据存储区中的偏移量指定的位置进行重组,直到没有分片。

       如果计数器超时或者分片保持尚未认可状态,则数据报会被丢弃。

如何重组:在接收方将分片重组好才可以交给上层协议,待重组的分片用一个ipd结构来保存。

为了高效的进行分片重组,ipd结构需要做到以下几点:

1.快速的定位某个数据报的一组所有分片

2.快速的在正确的数据报中插入新的分片

3.有效的判断某一个数据报的所有分片是否全部接收

4.具有组装超时机制,如果在未完成组装时计时器溢出,则抛弃该组分片。








### 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 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值