绪论
"It does not matter how slowly you go as long as you do not stop." 。本章是自上而下的进入网络协议栈的第三个篇幅--网络层--,本章我将带你了解网络层,以及网络层中非常重要的IP协议格式和网络层的分片组装问题,后面将持续更新网络层敬请期待,早关注不迷路。
话不多说安全带系好,发车啦(建议电脑观看)。
OSI定制的七层网络协议栈(其中上三层合并为应用层):
网络层
网络层其简单理解就是在复杂的网络环境中确定一个适合的路径
其中典型的协议就是IP协议
IP协议
从上图(网络通信过程)中不难观察出,发送报文就像我们走路一样是需要选择路径的,对于报文传输路径的选择就是基于IP协议
IP协议能力:
将数据包跨网络从B主机送到C主机,并选择优秀的路径
(但注意的是并不一定100%能将报文送达)
可以把传输层和网络层看成:
父亲希望儿子能考个好大学:
父亲:提供可靠的策略:保证能上学
张三:提供执行能力:努力学习考大学
父亲 对应的就是:Tcp,提供可靠的方案保证报文能高效、准确的送达。
儿子 对应的就是:Ip,进行路径的选择。
Tcp + Ip : A -> B
目的:将数据包可靠的从A->B主机
- IP地址 = 目标网络 + 目标主机
目标网络:网络号
目标主机:主机号(先有印象即可后面在网段划分处细讲) - 网络号: 保证相互连接的两个网段具有不同的标识(也就是所谓的网段(IP地址和子网掩码相与),相同网段下不能出现重复主机号)
- 主机号: 同一网段内, 主机之间具有相同的网络号, 但是必须有不同的主机号(可以大概理解成一个地方不能出现重复的东西)
注意的是:
- 网络不是凭空产生的,有人专门建设(由运营商建设)
- 网络世界是被精心设计过的和操作系统一样
一些基本概念
- 主机: 配有IP地址, 但是不进行路由控制的设备;
- 路由器: 即配有IP地址, 又能进行路由控制;
- 节点: 主机和路由器的统称;
协议头格式
只要有协议就离不开:
- 如何报头和有效分离
- 如何将有效载荷正确的分用
分离:通过 首部长度和16位总长度:
- 4位首部长度:单位是4字节,因为有4位就有(2进制化10进制):[0,15] 再乘上单位 * 4 = [0,60] byte,也就是报头最大长度是60字节,而其中报头固定长度至少有 20 byte、剩下的就是可选项的大小
- 16位总长度:16位总长度 = 报头长度(包含选项) + 有效载荷(所以也就是)
其余协议字段:
-
8位协议:发送方填充,表示上层协议类型(因为双方主机必须用同一种传输层协议,即主机A的传输层协议是TCP,则接收方也要用TCP协议才行 ),用于判断交给那个协议。
-
4位版本:填4就表示IPv4
-
8位服务类型(Type Of Service): 3位优先权字段(已经弃用), 4位TOS字段, 和1位保留字段(必须置为0)。所以主要的就是4位TOS(转发策略)它分别表示: 最小延时, 最大吞吐量, 最高可靠性, 最小成本。这四者相互冲突, 只能选择一个。(在不同路由转发中选用不同的策略来适应不同的场景)
例:对于ssh/telnet这样的应用程序, 最小延时比较重要; 对于ftp这样的程序, 最大吞吐量比较重要。
-
8位生存时间(Time To Live, TTL): 数据报到达目的地的最大报文跳数。一般是64。每次经过一个路由,TTL 就减 1,一直减到0还没到达, 那么就丢弃了。这个字段主要是用来防止出现路由循环(也就是转发出问题了,转发报文是要消耗资源的,所以就需要销毁)。
-
16位头部校验和:使用CRC进行校验,来鉴别头部是否损坏(不用因为tcp协议也会进行校验)。
-
32位源地址和32位目标地址: 表示发送端的ip地址和接收端的ip地址(端口号填到了传输层的16位源端口和目的端口)
其中还剩的ip协议中的三个字段:
16位标识、3位标志、13位偏移位,就是用来解决分片组装问题的!
让我们继续往下看
网络层的分片和组装问题
数据链路层限制:报文(数据帧)在网络中传输不能过大。
对此网络层的分片就是为了应对数据链路层中对帧的限制做出的处理方法,他将过大的报文就行分片,从而满足数据链路层的条件。
从而产生了一系列问题:
- 网络层分片后,当传递到对方主机后,同样在对方网络层就需要重新将分片的数据帧进行组装
- 从数据链路层知道了报文的最大大小,从而对于网络层、传输层、应用层都会有对应的大小设置(因为在每一层上都要至少加上报头固定大小)
具体如下图:
分片和组装都是在双方的网络层进行的,除了网络层外的协议层是不知道的(传输层就是直接把一个报文给到网络层,网络层处理再发给数据链路层)
分片的具体过程
分片是不好的,他提高了丢包的概率,他应该是网络通信的小概率事件。
如何尽可能不分片呢?
控制tcp,也就是tcp发送报文,不能只按照接受能力,直接发送一个大报文,必须按照自己的分片可能性,设置自己数据段的大小(当数据链路层的数据帧限制为1500byte时:1460byte 就是 tcp传送数据的最大段尺寸(MSS))
其中我们先认识下面三个字段:
- 16位标识(id):唯一的标识主机发送的报文。如果IP报文在数据链路层被分片了, 那么每一个片里面的这个id都是相同的。
- 3位标志字段:
- 第一位保留(保留的意思是现在不用, 但是还没想好说不定以后要用到)。
- 第二位置为1表示禁止分片, 这时候如果报文长度超过MTU, IP模块就会丢弃报文。
- 第三位表示"更多分片",如果分片了的话,最后一个分片置为1,否则是0。类似于一个结束标记.
- 13位分片偏移(framegament offset) :是分片相对于原始IP报文开始处的偏移。
- 其实就是在表示当前分片在原报文中处在哪个位置。
- 实际偏移的字节数是这个值 * 8(为了防止该报文的前一个报文大于2^13^,从而13位的偏移量不够表示。因为13位片偏移只有2^13^ ,而协议中的字段16位总长度最大为(2^16^)byte时,他是不够表示的,所以乘8(2^3^)补上差的3位。
- 注:用的时候:将真正的偏移量除8得到13位分片偏移,再后面还原时乘8得到真正的偏移量)。因此,除了最后一个报文之外,其他报文的长度必须是8的整数倍(乘8了就肯定是其整数倍,否则报文就不连续了)。
具体如下:
如何确定接受到的报文分片了呢:
- 收到的分片时看3位标志中的"更多分片"标志位:若是1就表示分了片。
- 若更多分片是0:则看13位偏移量是否大于0,大于0则表示他是该16位标识的结尾
如何确定收全了
- 能确定收到开头(标志位位001、片偏移位0)
- 能确定收到结尾(标志位为001、片偏移非0)
- 也能确定收到中间分片(按照片偏移进行排序,然后进行计算(片偏移等于前面分片的片偏移 + 有效载荷(除去ip报头的分片)))
- 最后在直接根据片偏移组合起来
TCP 和 IP在格式上有点像,并且要将报文从A->B就需要:网络的核心能力也就是:TCP/IP协议
附:协议报文封装的过程:
本章完。预知后事如何,暂听下回分解。
如果有任何问题欢迎讨论哈!
如果觉得这篇文章对你有所帮助的话点点赞吧!
持续更新大量Linux细致内容,早关注不迷路。