zoukankan      html  css  js  c++  java
  • TCP/IP 协议难点之一—— IP分片

    1 IP协议简单介绍

    就个人而言,网络中,抛开网络安全加密这些,就只单单讨论协议本身,比较难的有三个地方: 

    • IP分片与重组
    • TCP滑动窗口与TCP状态的改变
    • TCP定时器

    其实协议本身根据《TCP/IP详解卷1》理解起来并不难,但是实现起来就很难:数据的操作,标志位的设置,网络状态的变换,中断多线程通讯等等;

    在下图的七层网络协议参考模型中,IP层属于网络层,网络层最主要的作用就是:将指定IP的数据报传输到对应的主机。

    网络七层参考模型

    下图是以太帧封装格式(RFC 894),RFC 894封装格式也是我们最常用的。

    下面做个简单介绍:

    • 目的地址:6字节,即我们常说的以太网物理地址,这里是目标主机的物理地址,物理地址为唯一的。大家可能疑惑,发送网络数据时只写了IP地址,并没有写目的地址啊。这个是底层协议实现的,根据ARP协议,首先将目的地址设为全1,然后根据IP地址来获取目的地址。
    • 源地址:6字节,发数据时自己的物理地址。
    • 类型:2字节,协议类型,比如0x0800代表IP协议,0x0806代表ARP协议等等
    • 数据:802.3标准规定,一个以太帧最少64字节,最大1518字节,那么去掉6字节目的地址、6字节源地址、2字节类型、4字节CRC,对应区间即为48~1500字节,如果不足48字节可以填充。
    • CRC:顾名思义,校验部分,所以网络数据是很准确的,而且绝大多数都支持硬件CRC校验,速度非常快,几乎不会在这上面消耗时间。

    下面再看看数据部分:IP数据报

    IP数据报封装

    图中从左到右为0~31位,共四个字节,从上到下依次增长,IP头部占20字节,剩下的为数据,如果传输层为TCP则还有20字节的TCP头部,如果是UDP则还有8字节(如果分片的话,中间的包没有UDP头部,即0字节)的UDP头部。剩下的才是真正的用户要传送的数据。可以看出传送同样多的数据,UDP协议要比TCP传送的数据多,但从这一点来说UDP速度也要比TCP快。

    下面对一些字段做个简单介绍:

    • 4位版本:比如IPv4、IPv6
    • 4位手部长度:指的是首部占32 bit字的数目,包括任何选项。由于它是一个4比特字段,因此首部最长为60个字节
    • 16位总长度:一共16位,理论最大长度为65535字节,但是受硬件限制,和其它方面的考虑,大部分路由器或主机支持8192字节。
    • 3位标志:标识是否IP分片.第一位无用,第二位0:允许分片,1:不允许。第三位0:最后一片,1:后面还有分片
    • 13位片偏移:此分片在原始数据的偏移,用于分片重组,因为13位,所以支持的最大字节为8192
    • 8位生存时间TTL:规定网络数据包在网际层传输时,最多可以经过路由器的个数,它的大小一般为256/64,每经过一个路由值就会减1,当它为0时,数据会被丢弃,并回传一个ICMP包来通知发送者。

    2 IP分片

    从上面的介绍我们知道,一个以太帧最大为1518字节 (14字节以太首部,20字节IP首部,UDP8/TCP20,因此IP包每次最大为1500==MTU。去掉协议头UDP有效数据1472字节,TCP为1460字节。还有最后的4字节CRC),但是一个IP数据报则可能会有8192字节,超过以太帧的最大限制,那么这时就需要IP分片,分批进行传输。

    发送方会在IP层将要发送的数据分成多个数据包分批发送,而接收方则将数据按照顺序再从新组织起来,等接收到一个完整的数据报之后,然后再提交给上一层传输层。

    注意,TCP协议为可靠的传输协议,它避免了IP分片的发生,它会在TCP层对数据进行处理,对数据进行分段(不在详述),IP分片用的多的在UDP协议

    我们知道,协议本身并没有对数据在各个层中间怎么传递做出要求,比如嵌入式实现和BSD实现就不太一样,因为嵌入式内存比较少,数据在层与层之间传递时会尽量避免数据拷贝,而只是指针的操作。下面我们以嵌入式中用的比较多的LwIP举例

    LwIP允许的最大IP由如下决定:IP_REASS_MAX_PBUFS决定IP分片允许最大pbuf数量,IP_REASS_MAXAGE分片的生存时间,超过则错误并将之前接收的IP分片丢弃。

    如果数据大于IP_REASS_MAX_PBUFS则有两种选择,一,直接删除数据返回;二,是删除生存时间最长的IP分片PBUF,这个通过IP_REASS_FREE_OLDEST来使能。

    当为UDP协议时,如果缓冲区描述符大小小于完整的IP数据包,IP分片数据包到来时,很快将描述符耗尽,后来的IP包由于无缓冲区描述符而丢弃,UDP没有重传机制,很可能永远不会接收到完整的IP分片包。从而大于IP_REASS_MAXAGE出现错误,因此缓冲区描述符也应增大以适应IP分片重装。

    TCP发送数据时,将大于MSS的数据分段(segment不叫分片),MSS一般为1460.所以,TCP数据包不会在IP层分片。

    IP头部有3位标志字段,标志是否为分片包。第一位无用,第二位0:允许分片,1:不允许。第三位0:最后一片,1:后面还有分片。13位offset表示偏移,用于IP重组时数据排序,13位因此支持最大IP数据包为8192字节。

    标准的BSD协议实现如下图所示,采用两个结构体,IPQ为表头,将各个IP分片表头连接起来,并存储IP信息。Ipasfrag为具体的分片数据。

    BSD实现

  • 相关阅读:
    初识python 2.x与3.x 区别
    装饰器
    函数的进阶
    Spring Boot启动问题:Cannot determine embedded database driver class for database type NONE
    22.Spring Cloud Config安全保护
    23.Spring Cloud Bus 无法更新问题(踩坑) Spring cloud config server Could not fetch remote for master remote
    24.Spring Cloud之Spring Cloud Config及Spring Cloud Bus
    Spring Boot整合Spring Data Elasticsearch 踩坑
    项目中Spring Security 整合Spring Session实现记住我功能
    32.再谈SpringBoot文件上传
  • 原文地址:https://www.cnblogs.com/mddblog/p/4603164.html
Copyright © 2011-2022 走看看