引入:
IP协议主要解决什么问题呢?
IP协议提供一种将数据从主机A 发送到 主机B的能力。(有能力不一定能做到,比如小明很聪明,可以考100分,但是他也不是每次搜能考100分,可靠性由传输层来解决)
IP协议基本概念
**主机 :**配有IP地址, 但是不进行路由控制的设备;
**路由器:**即配有IP地址, 又能进行路由控制;
**节点 :**主机和路由器的统称。
IP协议头格式
1. 如何封装和解包呢?
定长报头+自描述字段(4位首部长度)
2. 如何交付?(如何确定交付的协议)
8位协议:标识UDP还是TCP
4位版本:
确定是IPv6还是IPv4
4位首部长度
IP头部的长度是多少个32bit, 也就是 length * 4 的字节数. (基本单位是4字节)4bit表示最大
的数字是15, 因此IP头部最大长度是60字节. 当4位首部长度值为 0101 时表示没有选项(20字节)
8位服务类型(Type Of Service):
3位优先权字段(已经弃用), 4位TOS字段, 和1位保留字段(必须置为0).
4位TOS分别表示: 最小延时, 最大吞吐量, 最高可靠性, 最小成本. 这四者相互冲突, 只能选择一个. 对于 ssh/telnet这样的应用程序, 最小延时比较重要; 对于ftp这样的程序, 最大吞吐量比较重要.
16位总长度(total length):
IP数据报整体占多少个字节.
16位标识(id):
唯一的标识主机发送的报文. 如果IP报文在数据链路层被分片了, 那么每一个片里面的这个
id都是相同的.
3位标志:
第一位保留(保留的意思是现在不用, 但是还没想好说不定以后要用到). 第二位置为1表示禁
止分片, 这时候如果报文长度超过MTU, IP模块就会丢弃报文. 第三位表示"更多分片", 如果分片了的话, 最后一个分片置为1, 其他是0. 类似于一个结束标记
13位分片偏移(framegament offset):
是分片相对于原始IP报文开始处的偏移. 其实就是在表示当前分片在原报文中处在哪个位置. 实际偏移的字节数是这个值 * 8 得到的. 因此, 除了最后一个报文之外, 其他报文的长度必须是8的整数倍(否则报文就不连续了).
8位生存时间(Time To Live, TTL):
数据报到达目的地的最大报文跳数. 一般是64. 每次经过一个路由, TTL-= 1, 一直减到0还没到达, 那么就丢弃了. 这个字段主要是用来防止出现路由循环。
8位协议:
表示上层协议的类型
16位头部校验和:
使用CRC进行校验, 来鉴别头部是否损坏.出错就会丢弃报文。
32位源地址和32位目标地址:
表示发送端和接收端.
选项字段(不定长, 最多40字节):
分片:
链路层因为其物理特性的原因,一般不会一次性转发太大的数据**==>**也就是说:
++链路层有一次可以转发到网络中的报文大小的限制++,一般是1500(MTU),所以网络层需要将一个较大的ip报文拆分成多个小的,符合条件的报文,这就是分片。
分片的行为是网络层完成的,上层的传输层和应用层并不知道,(这在一定程度上埋下隐患),同样组装的行为也必须由对方的网络层完成。
为什么呢?
原因可以分为2个:
1 、 对方给自己的是一个完整的TCP报文,那我自己上传输层交付时也必须是一个完整TCP报文;
2 、 协议具有一致性,IP协议负责分片和组装不会影响其他层的服务。
分片决定了网络层IP协议具有3种能力
1. 具有区分不同报文的能力 ----16位标识符
2. 具有判断报文是不是分片的能力 ----"更多分片"
3. 异常处理 ---- 任何一个分片丢失,都可以识别出来
怎么做到分片的呢?

3位标志中有一位是保留的,第2位为1时表示禁止分片,如果报文长度超过MTC,IP就会丢弃报文。第3位 表示 " 更多分片 " ,如果分片了的化,最后一个分片置为 0, 其他是 1,类似一个结束标记。
认识偏移量
开始: 更多分片 1 ,片偏移 = 0
结尾: 更多分片 0 ,片偏移 ≠ 0
++中间: 更多分片 1 ,片偏移 ≠ 0++
++中间那么多的分片,如何确定所有分片都收到了呢?++
根据偏移量进行升序排序,结合偏移量+自身大小=下一个报文的偏移量,通过扫描整个报文,来进行判断,如果不匹配,则说明报文出现了丢失,需要重新发送,如果成功遍历到结尾,则表明收取到了完整的报文。
分片之前,报文一定是一个完整的报文,分片之后,每一个分片也有单独的IP报头
下面简单分析一下分片过程
假设MTC=1500

原本的整个报文数据大小是 3000 ,(注意: IP报文=IP报头+有效载荷)
第一步,先分一个1500的数据块,直接拿走原本的报头(实际可能更复杂哈) ,
剩下的1500的数据并不是可以直接就成为一个分片,还要添加报头信息(20字节)为了支持未来的组装,每一个分片都必须有IP报头,所有分割1480的大小,再添加20字节的报头,最后一个分片包含20字节的报头和20字节的有效载荷。
我们再来分析一下这三个报文
|------------|------|------|------|
| 报文编号 | 1 | 2 | 3 |
| 16位标识 | 1234 | 1234 | 1234 |
| 3位标志"更多分片" | 1 | 1 | 0 |
| 13位片偏移 | 0 | 1500 | 2980 |
| 总长度 | 1500 | 1500 | 40 |
分片的坏处
之前我们提到在网络层进行分片和组装,上层是不知道的,同时,我们也应该有这个常识:
丢包是有概率的,分包会增加报文个数,在一定程度上增加了丢包的概率。,要彻底解决丢包问题,还得依靠 传输层。当然这也决定了分片不是主流。
网段划分
IP 地址分为两个部分 , 网络号和主机号
网络号: 保证相互连接的两个网段具有不同的标识 ;
主机号: 同一网段内 , 主机之间具有相同的网络号 , 但是必须有不同的主机号 ;
不同的子网其实就是把网络号相同的主机放到一起. 如果在子网中新增一台主机, 则这台主机的网络号和这个子网的网络号一致, 但是主机号必须不能和子网中的其他主机重复.
通过合理设置主机号和网络号 , 就可以保证在相互连接的网络中 , 每台主机的 IP 地址都不相同 .
那么问题来了 , 手动管理子网内的 IP, 是一个相当麻烦的事情 .
有一种技术叫做 DHCP , 能够自动的给子网内新增主机节点分配 IP 地址 , 避免了手动管理 IP 的不便 . 一般的路由器都带有DHCP 功能 . 因此路由器也可以看做一个 DHCP 服务器 .
过去曾经提出一种划分网络号和主机号的方案 , 把所有 IP 地址分为五类 , 如下图所示
|--------|---------------------------|
| A类 | 0.0.0.0到127.255.255.255 |
| B类 | 128.0.0.0到191.255.255.255 |
| C类 | 192.0.0.0到223.255.255.255 |
| D类 | 224.0.0.0到239.255.255.255 |
| E类 | 240.0.0.0到247.255.255.255 |
随着 Internet 的飞速发展 , 这种划分方案的局限性很快显现出来 , 大多数组织都申请 B 类网络地址 , 导致 B 类地址很快就
分配完了 , 而 A 类却浪费了大量地址 ;
例如 , 申请了一个 B 类地址 , 理论上一个子网内能允许 6 万 5 千多个主机 . A 类地址的子网内的主机数更多 . 然而实际网络架设中, 不会存在一个子网内有这么多的情况 . 因此大量的 IP 地址都被浪费掉了 .
针对这种情况提出了新的划分方案 , 称为 CIDR(Classless Interdomain Routing):
引入一个额外的子网掩码 (subnet mask) 来区分网络号和主机号 ;
子网掩码也是一个32 位的正整数 . 通常用一串 "0" 来结尾 ;
将 IP 地址和子网掩码进行 " 按位与 " 操作 , 得到的结果就是网络号 ;
网络号和主机号的划分与这个 IP 地址是 A 类、 B 类还是 C 类无关 ;
示例1
可见 ,IP 地址与子网掩码做与运算可以得到网络号 , 主机号从全 0 到全 1 就是子网的地址范围 ;
IP 地址和子网掩码还有一种更简洁的表示方法 , 例如 140.252.20.68/24, 表示 IP 地址为 140.252.20.68, 子网掩码的高24位是 1, 也就是 255.255.255.0
特殊的IP地址
将 IP 地址中的主机地址全部设为 0, 就成为了网络号 , 代表这个局域网 ;
将 IP 地址中的主机地址全部设为 1, 就成为了广播地址 , 用于给同一个链路中相互连接的所有主机发送数据包;
127.* 的 IP 地址用于本机环回 (loop back) 测试 , 通常是 127.0.0.1