1.前言
我们的LINUX网络系列已经介绍完了应用层HTTP,传输层TCP/UDP,接下来就网络层IP进行较为详细的学习笔记。
HTTP应用协议解决了如何把HTML/CSS等资源用起来,HTTP服务器也自带解决TCP字节流的粘包问题,让我们“看到了”整个网页;TCP和UDP则是更是起到了传输控制的作用(当然UDP本身没怎么管,TCP在这方面做的很好),并且通过学习TCP报头我们也知道了,TCP只解决端口到端口的问题(原port,目的port),网络层解决的就是IP到IP的问题。
比如: 为什么要主机B要把内容交给路由器F,路由器F凭什么要交给路由器G呢?
路由器之间是如何联系、互相选择的?
每个路由器之间具体怎么传的,就是数据链路层,具体传输的都是MAC帧,这会在以后的文章中做解释。
因为目标决定路径。
在完成TCP或者HTTP服务器的时候我们有了解过,IP(IPV4)的格式是点分十进制的,比如
131.46.2.77,每一个都是在[0,255].[0,255].[0,255].[0,255]的范围中构成的,每一个IP都标识了主机的唯一性,255是八位二进制数,所以一共就是32位二进制数构成一个IP地址。
现在,说的都是“公网IP”——全球内具有唯一性的IP,还有一个局域网IP的概念,我们会在后文介绍。
两个基本概念
主机: 配有IP地址, 进行路由控制的设备;路由器: 即配有IP地址, 又能进行路由控制;节点: 主机和路由器的统称;
所以其实路由器就是一个主要用于转发、路由消息的“主机”
现在需要解决的两个大问题:
在图中,B为何选择将报文转发给F?具体通过什么路径传输?如何将F中的数据传递到G?
在网络概论中了解到,相邻的、能直接发送数据的主机必然位于同一子网内,所 有子网内的局域网通信共同构成了完整的网络通信体系(可以认为每个黑框就是一个局域网),无数个这样的局域网互联便形成了整个网络。而路由选择由IP层(即网络层)负责处理。
严格来说,路由器本身并不生成子网。子网的划分是通过网络管理员根据IP地址和子网掩码(后文有介绍)来配置的。
路由器的作用是根据这些配置来连接和管理这些子网,所以我们暂且认为每个路由器下都可以有自己的子网
当图中的任意一个路由器收到报文,必然要判断两件事:1.这个报文是不是我这个路由器(及其子网下的)? 2. 如果是,是我子网下的哪一个机器?
所以,IP地址本质分成两部分,既 32位IP号 = 目的IP + 主机IP,就像你说你要从云南去北京天安门,在路上你只会先买“去北京的车票”,而不是直接买“去北京天安门的车票”,等到了北京,再去找如何去天安门。
网络层要解决的就是,根据网络IP,根据 目的IP+主机IP 进行路由选择
关于TCP和IP的关系,再次理解:
重谈TCP和IP
TCP的一个核心逻辑就是控制是否丢包,但是IP层是不关心丢包问题的,对于IP来说,丢就丢了,完全不用处理,这是TCP的事情——TCP是一种决策,IP+MAC才是去执行
所以,IP其实是提供了一种能力——一种选择路由路线的能力,但是有能力不代表一定能做到。在网络这个复杂的大环境中,IP也有出问题的时候,这个时候依然需要回到TCP层次去解决问题。(现代的IP可能也有自己的解决办法,如ICMP。ICMP消息通常是在IP数据报传输过程中出现问题时生成的,例如数据报无法到达目的地、数据报超时等)
这样的分层设计哲学是非常精妙优雅的,
- IP协议(网络层)职责:只负责数据包的路由和传递,提供"尽力而为"的无连接服务(现代的差分服务 有调整 传统的“尽力而为”无连接服务)
- TCP协议(传输层)职责:负责端到端的可靠传输,包括流量控制、拥塞控制和错误恢复
这样让路由器不用去维护复杂的传输控制,而只需要专注于高效转发;有时候也想不用TCP而采用UDP,这样的分层设计可以让IP直接和UDP搭配使用
基于以上基本概念,我们详细的来学习一下基础的IP协议。
2. IP协议报
正如之前所了解的,每一层解决不同的问题,每一层都要加不同的报头。
应用层进行对应的序列化和反序列化;传输层进行对应的发送控制,如流量控制,拥塞控制等等。当下的网络层,就是把传输层——比如TCP协议中的滑动窗口中并发的内容进行路径选择。
TCP层次我们讲数据段,segment;现在网络层更喜欢叫数据包,packet;在下一层(数据链路层称之为mac)
IP层报头:
4位版本号 (version)指定 IP 协议的版本 , 对于 IPv4 来说 , 就是 4这个值在绝大部分情况下都是IPv4, 因为IPv6和IPv4在结构上是不兼容的( IPV6是128位比特位,解决IP号不足的问题 ),这也就意味着如果使用IPv6就需要使用一套新的结构,同时为了从该结构中读取到内容就需要新的解决方案,整个过程迭代太复杂(不要和TCP的16位窗口用M因子左移控制搞混淆了)4位头部长度 (headerlength)IP头部的长度是多少个 32bit(这一点不要记混了,4位的做法和TCP层次是一样的,4位数据*4b,让报头长度扩展到最多60字节,而IP基本报头长20字节,还可以有40字节的选项字段)8位服务类型type of service(TOS)字段,用于指示如何处理数据包,主要是关于处理数据包的策略:前3位:优先级(Precedence),定义数据包的重要性(已经弃用)
接下来4位:服务类型标志,包括:
D位(Delay): 表示延迟敏感度,1表示低延迟
T位(Throughput): 表示吞吐量要求,1表示高吞吐量
R位(Reliability): 表示可靠性要求,1表示高可靠性
M位(Monetary Cost): 表示成本偏好,1表示低成本
最后1位:保留位,通常设置为0最小延时,最大吞吐量,最高可靠性, 最小成本.这四者相互冲突,只能选择一个.对于ssh/telnet这样的应用程序,最小延时比较重要;对于ftp这样的程序,最大吞吐量比较重要
现代网络中,TOS字段已演进为差分服务(DiffServ)字段,其结构如下:前6位:差分服务代码点(DSCP),用于标识服务等级 后2位:显式拥塞通知(ECN),实现拥塞反馈机制
该字段赋予网络设备(如路由器)以下能力:
- 保障实时业务(如VoIP实时语音)的低延迟传输
- 提升大容量数据流的传输效率
- 为关键业务分配优先级资源
- 实施精细化的服务质量(QoS)策略
早期互联网中TOS字段应用显的比较鸡肋,但随着网络拥塞问题日益突出,差分服务模型已成为现代网络流量管理和服务质量保障的核心机制。
以下内容了解即可:
差分服务(Differentiated Services,DiffServ)是一种网络服务质量(QoS)策略。它主要是通过在IP网络中对数据包进行分类和标记,然后根据这些标记来提供不同级别的服务。这种策略允许网络运营商根据用户的业务需求和优先级来分配网络资源。
例如,可以将来自特定服务器的视频流媒体数据包归为一类,将网页浏览的数据包归为另一类。可以将视频流媒体数据包的DSCP字段设置为一个较高的值(如46,表示 Expedited Forwarding,加速转发类别),而将网页浏览数据包的DSCP字段设置为一个较低的值(如0,表示默认类别)
继续回归IP报头,先跳过第二个八字节
8位生存时间:
先了解一般情况下在网络传输中会遇到的一种问题:数据包无限循环
所谓数据包无限循环是指数据包从一个路由器传输到下一个路由器时被下一个路由器继续传输到先前的路由器,如此循环
如果有大量数据包在网络中出现无限循环的情况就会导致网络拥塞。为了尽可能防止这个问题,为每一个数据包设置了一个计数器,每当数据包经过一个路由器,这个值就减1,如果这个值减到了0,那么路由器就会丢弃该数据并返回ICMP超时消息,这个值就是生存时间(Time to Live)
8 位协议 : 表示上层协议的类型
16 位头部校验和 : 来鉴别头部是否损坏 .32 位源地址和 32 位目标地址 : 表示发送端和接收端 .
关于解包和分包的问题:
首部长度+16位总长度-》解决解包和封包问题。
3. 网段划分
核心思想:网络是被人设计过的。
所以任何的子网划分等,都只不过是人为设计的一个策略
刚刚有提过:
IP地址分为两个部分,网络号和主机号
网络号 : 保证相互连接的两个网段具有不同的标识 ;主机号 : 同一网段内 , 主机之间具有相同的网络号 , 但是必须有不同的主机号 ;
图中的24表示的是二进制位数,表示前24位是网络标识不同的子网其实就是把网络号相同的主机放到一起
一个路由器可以管理多个子网,路由器也是当前网段里第一个入网的设备,所以特殊地,路由器的IP都是xx.xx.xx.1,表示是当前子网的第一个设备。
往上宏观的看,上图就是一个一个的局域网(LAN),局域网之间除了路由器,还需要依靠广域网(WAN)连接起来,到这一步就要引入一个关键人物:运营商,在国内主要就是电信联通移动三家公司,作为三家巨头一级运营商
运营商们提供广域网(WAN)服务,连接不同的局域网(LAN)和用户设备,实现互联网的接入和数据传输。它们的网络基础设施包括光纤、基站、路由器、交换机等,覆盖全国乃至全球范围。
网络的通信过程本质上涉及不同局域网之间的主机交互。通过对这一机制的分析,我们发现IP地址可以采用"网络号+主机号"的分段方式来实现网段划分。
这种划分方式在数据传输时具有显著优势:在报文到达目标局域网时,仅需比对目标网络号是否匹配。若当前网络号与目标不同,则无需逐个比对局域网内的所有主机IP,从而大幅提升传输效率(因为大量的增加了淘汰的效率!)。当数据抵达目标局域网后,再通过主机号进行精确匹配即可完成通信。
路由的基本单位就是网络,把IP地址分成若干位,前面一部分作为子网的入口,路由器中添加对应的配置信息,就实现了网段划分
有了基础的理解,下面来看下具体的划分原理
划分原理
了解了网段划分后现在的问题就是:多少位是局域网地址,多少位又是主机地址呢?
在先前,有这样一种划分网络号和主机号的方式:
将IP地址分为5类IP,分别对应着A类地址、B类地址、C类地址、D类地址和E类地址,如下图所示:
A 类 0.0.0.0 到 127.255.255.255B 类 128.0.0.0 到 191.255.255.255C 类 192.0.0.0 到 223.255.255.255D 类 224.0.0.0 到 239.255.255.255E 类 240.0.0.0 到 247.255.255.255随着 Internet 的飞速发展 , 这种划分方案的局限性很快显现出来 , 大多数组织都申请 B 类网络地址 , 导致 B 类地址很快就分配完了 , 而 A 类却浪费了大量地址 ;
CIDR
针对上面这种问题,提出了一种解决方案:CIDR(Classless Interdomain Routing)。在这个方案中,提出了子网掩码(Subnet mask)的概念,子网掩码的作用就是区分出主机号和网路号,其也是32位正整数,一般以一串0结尾,具体区分方式为:将IP地址与子网掩码做按位与&运算,得到的结果就是网络号,因为可以规定子网掩码1的个数来决定网路号,所以这样一来就不需要确定是哪一类地址来区分网络号的位数,例如下面的两个例子:
可见 ,IP 地址与子网掩码做与运算可以得到网络号 , 主机号从全 0 到全 1 就是子网的地址范围 ;IP 地址和子网掩码还有一种更简洁的表示方法 , 例如 140.252.20.68/24 , 表示 IP 地址为140.252.20.68, 子网掩码的高 24 位是 1, 也就是 255.255.255.0
后文开始,只考虑子网掩码的方案。
两个特殊的IP地址
主机号为全0或者全1其实是特殊IP
理论上,该网段下,抛开一个网络号和一个广播地址,是256-2=254个有效的可利用地址
例子二中,子网掩码就该写成28
这样操作的好处是,每次可以先通过网络号比较,淘汰掉大部分根本就不在一个网段的情况,从而增加匹配效率。
尽管上述操作有效缓解了IP数量不足的问题,但是能接入公网的IP数量任然不足2^32个,还要去掉一些特殊IP,现在暂时有三种策略:
1、动态分配IP地址:只给接入网络的设备分配IP地址。因此同一个MAC地址的设备,每次接入互联网中,得到的IP地址不一定是相同的
2、NAT技术:NAT(Network Address Translation),允许多个设备共享较少数量公网IP地址的技术,后面会重点介绍,本篇不做介绍
3、IPv6技术:不实用原因前面已经提及,此处不再说明
私有IP地址和公网IP地址
如果一个组织内部组建局域网,IP地址只用于局域网内的通信而不直接连到Internet上,理论上使用任意的IP地址都可以,但是RFC 1918规定了用于组建局域网的私有IP地址:
10.*,前8位是网络号,共16777216个地址
172.16.*到172.31.*,前12位是网络号,共1048576个地址
192.168.*,前16位是网络号,共65536个地址
1. 私网
在上面范围内的IP地址全部是私有IP地址,其他都是公网IP地址。需要注意的是,私有IP地址只能用来组建局域网,不能出现在公网中,这也就意味着不同的局域网可以使用相同的私有IP地址从而达到了IP地址的复用的目的,而有构建局域网能力的设备就是路由器,每一台路由器都有DHCP(Dynamic Host Configuration Protocol)功能,有了这个功能,路由器就可以动态为当前局域网内的主机分配IP地址
基于上面的概念,再看最开始提到的两台主机通信的过程:
在上图中,因为路由器具有组建局域网的能力,所以一台路由器和其对应的主机就属于一个局域网,在同一个局域网下的所有主机的网络号就是相同的。由于网络的建设在宏观上看都是这种层状的,所以192.168.1.201/24所在局域网的路由器——192.168.1.1/24,一定是上一层的一个节点(既是上一层的节点,又是更上层的这个局域网---10.1.1.*的节点)。我们称前者是LAN口IP,后者是WAN口IP
比如最左边的192.168.1.201/24想给122.77.241.3/24发消息,.201这个主机首先判断出
122.77.241.3/24
不属于当前局域网,将数据交给IP地址为192.168.1.1/24
的路由器。这个地方就涉及到一个缺省路由和默认网关的概念,其实这两个是一个东西,就表示在当前的路由表中没有找到对应的目标IP时,直接发给默认网关,而这个默认网关就是当前局域网的路由器,由上一层的路由器再去判断192.168.1.1的路由器收到之后,这里需要提醒一点:因为私网IP不能出现在公网中,而IP协议报中的字段需要有源IP地址,所以路由器在对数据进行转发时需要将198.168.1.201/24转换为WAN口IP地址,即10.1.1.2/24,接着继续判断发现122.77.241.3/24依旧不属于当前局域网(即路由器10.1.1.1/24组建的局域网),需要将数据交给路由器10.1.1.1/24由其进行转发,现在又到了需要IP转换的时候,不过此时的路由器是一个WAN口IP为公网IP的路由器,一般是各个组织、公司等企业级别的路由器,这样IP就转换成
122.77.241.4/24
,最后传输到公网上,找到了公网IP地址为122.77.241.3/24
的设备。最后122.77.241.3/24
设备收到的IP协议报中的源IP地址为122.77.241.4/24
而不是一开始的198.168.1.201/24
至于回消息的过程如何回来,涉及到内网转发和NAT的知识,我们会在之后的文章中介绍。
可以在自己的机器上查看:
刚刚的那个结构是相对于简单的,其实运营商的服务器可以不停的往上搭建,可以建立很多层再到该运营商的入口路由器。
所以,我们从家里的路由器发出去的内容,并没有直接到达公网,而是先到运营商构建的子网中去:1.如果你的账号欠费了,直接把你的任何request都丢弃在当前的路由器中,从而无法上网;2.如果访问的资源是非法的,比如是国外网站,也可以直接拦截你,所以挂梯子其实就是绕过运营商去上网。
2. 公网(重点!梳理了公网和私网的不同)
进一步理解公网的IP:
IP号是一种有限且有用的资源,主体上是以国家为单位申请,但是诸如清华大学、腾讯阿里等也会直接有。我们甚至可以直接在百度上查到IP资源的分配情况,一般来说,越发达的国家所占有的IP资源就会越多
每个接入公网的路由器,比如以国家为单位的国际路由器,而这些大型的路由器之间的联系,往往就需要用到大量的光缆去连接
再来理解一下全球网络:
这里的公网IP就和刚刚的局域网IP不一样了,每个路由器的IP号都不一样
每当一个路由器上线,就在当前子网中直接进行广播,进行广播的前提就是路由表中有其他各个接口的信息
路由表条目中其实并不存在所谓的地区,但是还有一个“下一跳”。
这里要理解一个问腿,公网的子网和私网的子网是不一样的:私网的子网,在物理的路由器上距离很近(比如家里的路由器+你的电脑+你爸爸的手机+你狗狗的电话手环);公网的子网在路由器的物理距离上则非常遥远,比如上图的国际路由器,那么他们如何连接到一个子网中去呢?比如中国和俄罗斯,可以建基站拉光纤,像中国和漂亮国这种,就需要卫星和海底光纤进行连接:但是距离的遥远导致,公网·的子网中的各个节点的网络号是不一样的!
所以我们发现,同一个公网的子网中,大家的网络号可以不一样;而私网中,大家的网络号是一样的。所以私网都属于一个网段,因为这是网段的定义:
不过在日常中,也可以认为这些在不同网段的公网节点“也在一个网段”,但是严格意义上来说是不在一个网段的
在全球网络的DEMO中,一个节点上线就会进行广播,通知该子网的所有内容,比如我们再从国际级别的路由器下降到中国省级的路由器
这里的每一个6.*.0.0,代表的就是当前网络号。6.*.0.1,可以看作是运营商的出入口路由器
假设省级以下就直接进入私网:
当你的消息发出去,到达运营商路由器出入口(也就是省级路由器),和省级路由器的路由表条目中的掩码依次按位与,找到满足条件的接口,直接接入即可。
整个转发过程:同一子网中是不需要经过 "头头上的路由器" 的,直接通过最后一IFACEACE转发即可
可以在LINUX机器下使用route指令查看当前机器的路由表(博主这里是腾讯购买的云服务器,所以直接可以连接到公网)
在上面图中,每一个字段表示的含义如下:
Destination:表示目标网络或目标主机的地址,其中default 表示默认路由,适用于所有未匹配到具体目标的流量
Gateway:表示下一跳的网关地址。如果是0.0.0.0,表示目标网络在本地网络中,无需通过网关转发。_gateway 是网关的别名,通常指向默认网关
Genmask:表示子网掩码,用于确定目标网络的范围。例如,255.255.255.255 表示单个主机,255.255.240.0 表示一个子网
Flags:表示路由的标志,常见值包括:
- **U**:路由是活动的(Up)
- **G**:路由需要通过网关
- **H**:目标是一个主机
- **UH**:目标是一个主机且路由是活动的
Metric:表示路由的优先级,值越小优先级越高,用于在多条路由中选择最佳路径Ref:表示路由的引用计数,通常用于调试目的。在现代Linux系统中,这个字段通常为0
Use:表示路由被使用的次数。用于统计路由的使用频率
Iface:表示出接口,即数据包通过哪个网络接口发送。例如,eth0 表示通过以太网接口发送
其实每个路由器都有至少两个IP地址,比如刚刚的图里,私网服务器都至少一个WAN一个LAN,有的路由器还能连接更多2,这个是根据路由器的能力而定的,家庭路由器的承载能力一定比不过国际路由器
中国国际路由器是x.x.x.x/8的,但是对于省级来说,他一定还有一个x.x.x.x/16的IP地址,和国内的其他路由器就可以处于同一个“层状”
需要注意,公网IP地址实际上并不只是按照国家划分,更多还是根据机构、学校等划分,国内也不只是按照省份、州等进行划分
4.IP分片与组装
IP的分片与分装,都是依靠第二个八字节的16位标识、3位标志、13位片偏移共同维护的
16 位标识 (id): 唯一的标识主机发送的报文 . 如果 IP 报文在数据链路层被分片了, 那么每一个片里面的这个 id 都是相同的.3 位标志字段 : 第一位保留 ( 保留的意思是现在不用 , 但是还没想好说不定以后要用到 ). 第二位置为 1 表示禁止分片(以下讨论默认第二位是0) , 这时候如果报文长度超过 MTU, IP 模块就会丢 弃报文. 第三位表示 " 更多分片 ", 如果分片了的话 , 最后一个分片置为 0, 其他是 1 类 似于一个结束标记.13 位分片偏移 (framegament offset): 是分片相对于原始 IP 报文开始处的偏移 .其实就是在表示当前分片在原报文中处在哪个位置 . 实际偏移的字节数是这个值 除以 8 得到的 . 因此 , 除了最后一个报文之外 ( 之前如果都是 8 的整数倍,最后一片的偏移量也一定是 8 的整数倍 ), 其他报文的长度必须是 8 的整数倍 ( 否则报文就不连续了 ).
为什么要分片
当一个 IP 数据报的大小超过了网络的 MTU( 最大传输单元,在Linux中,这个值一般是1500字节。减去不考虑带选项的IP协议报大小20字节,剩下的数据最大只能为1480字节 )限制时,就需 要进行分片。MTU 是数据链路层对 IP 层数据包进行封装时所能接受的最大数据 长度。此时就有问题了:TCP层次明明控制了传输大小,为什么还要在IP层分片?IP层不是只负责“尽力而为地传输”吗?
TCP层会根据MSS值和应用层的数据需求,将数据分割成多个数据段,每个数据段的大小不超过MSS值;如果对TCP滑动窗口还有印象的读者会记得,每一个滑动窗口都会划分成一小个小个的segment,原因就是考虑数据链路层的问题——所以,数据链路层的问题已经被考虑过,分片不是我们希望出现的情况!
分片会带来很多的坏处:
分片会增加网络的处理负担,因为每个分片的数据包都需要单独处理。
分片的数据包在传输过程中可能会丢失或乱序,这会增加重组的复杂性。
所以,不得不进行分片的情况其实是:不同的节点的MTU可能变化,不过一般的正常通信都是一样大的;UDP更容易出现分片,因为UDP要传的数据都是定长,不会控制。
MTU限制:
不同的网络链路有不同的MTU值。例如,以太网的MTU通常是1500字节,而串行链路的MTU可能更小。
如果TCP层发送的数据段大小超过了路径上某个链路的MTU值,IP层必须将数据段分割成多个较小的数据包,以适应链路的MTU限制。这个过程称为分片(Fragmentation)。
路径MTU(PMTU):
路径MTU(Path MTU)是指从源主机到目的主机路径上允许通过的最大数据包大小。
路径MTU可能会小于源主机的MTU值,因为路径上可能存在MTU值较小的链路。
IP层需要根据路径MTU进行分片,以确保数据包能够顺利通过整个路径。
可以在LINUX中ifconfig查看mtu
如何进行分片?
首先,分片,分的只是TCP报文的数据(报头就20个字节,不会分!),分好的每一段,都会用一个单独的IP报头去加上,形成一个单独的IP数据包
重新解释16位标志位、3位标识、13位偏移三个字段的含义如下:
16位标识符:标记一组分片数据,同一组分片数据具有相同标识符。注意,未分片的数据该值也不为0。这个就很类似TCP的序号和确认序号,同一个TCP报文被分成IP报文时,具有的该16位序号(标识符相同)
3位标志:
- 第1位:保留待用
- 第2位:置1表示禁止分片
- 第3位:表示后续是否有更多分片(1表示有,0表示无)
13位片偏移:表示当前分片数据在整个数据中的偏移量。例如:
- 第一个分片的偏移量为0
- 后续分片的偏移量为前一个分片的偏移量加上前一个分片的大小
但存在一个问题:13位片偏移最大只能表示2^13,而IP协议报允许的最大数据大小为2^16。为解决这个问题,实际填入13位片偏移的值是2^16÷2^3=2^13。这样就能正确表示偏移量,在数据组装时需要将偏移量乘以8。
接收方判断数据是否分片的步骤如下:
- 第一个分片:标志位第3位为1,片偏移为0
- 中间的若干分片:标志位第3位为1,片偏移不为0
- 最后一个分片:标志位第3位为0,片偏移不为0 判断数据未分片的条件:标志位第3位和片偏移均为0
这就是IP分片设计的最牛逼的一点,直接判断标志位第三位和偏移量是否都为0即可!
基于上面的判断方式,接收方又如何知道自己收到了分片后的全部数据?可以考虑一种思路:对所有分片数据按照片偏移进行升序排序,如果缺少3位标志的最后一个1,就是没有最后一位;缺少片偏移为0,那么缺少的就是第一个分片数据;如果升序排序,片偏移量不连续,说明缺少中间分片数据
观察一次切片的过程;
假设今天是3020个字节,有20个报头,所以是3000b,先分出第一个16位标识6666(假设的),很明显不是最后一个,所以三位标识的末尾填1,片偏移为0,切记需要给这段的1480字节的数据加上一个20字节的IP报头,然后按照这个模式继续向后分片即可,比如第二个IP报文的片偏移就是1480,但是填的是185,因为片偏移都需要除以8,并且片偏移在设计时也都必须设计成8的倍数!
分片和组装不一定只需要发送方和接受方这么做,在中间的网络路由器中,也可能出现,因为中途路由器的MTU可能不同。综上,IP分片永远是不建议的做法,因为会增大UDP和TCP的丢包率。
此文中遗留了部分问题,会在之后的文章中解决