目录
IP协议
计算机网络分层
IP协议头格式
IP数据报 - 数据分片
数据报为什么要分片?
数据报分片是什么?
如何做到IP数据报分片?
分片demo示例
并不推荐分片,能不分片则不分片。
网段划分
前置了解
网络号和主机号
为什么要把IP地址分为网络号和主机号?(作用)
过去的一种划分网络号和主机号的方案,把所有的IP地址分为5类
无类别域间路由CIDR
特殊的IP地址
IP地址的数量限制
私有IP地址和公网IP地址
NAT
路由
IP协议
计算机网络分层
应用层解决的是数据使用的问题,比如http协议,报头中有字段标明有效载荷的数据类型,是html还是json等等,以及解决传输层TCP协议粘包问题,所以会在应用层协议中用一些方式标识每个应用层报文之间的边界。
下面三层:传输层,网络层,数据链路层。指的是网络通信的细节,可以将数据可靠的从A主机跨网络送到B主机。
而传输层主要作用就是制定传输的策略,如TCP协议就能保证可靠性。
而网络层的IP协议可以提供一种能力:将数据从A主机跨网络送到B主机的能力。(IP协议有能力,但并不是一定能保证送达,有概率丢包,此时,传输层的一些策略,比如TCP的超时重传,快重传等机制,就可以决定重新传,从而保证可靠性。)
(准确来说,IP协议并没有将数据从A主机送到B主机的能力,而是在复杂的网络环境中确定一个合适的网络传输路径。真正的传输是由数据链路层和物理层完成的。)
IP协议头格式
4位版本号(version): 指定IP协议的版本, 对于IPv4来说, 就是4.
4位首部长度(header length): IP头部的长度是多少个32bit, 也就是 length * 4 的字节数. 4bit表示最大的数字是15, 因此IP头部最大长度是60字节.(也就是选项最多40字节)
8位服务类型(Type Of Service): 3位优先权字段(已经弃用), 4位TOS字段, 和1位保留字段(必须置为0). 4位TOS分别表示: 最小延时, 最大吞吐量, 最高可靠性, 最小成本. 这四者相互冲突, 只能选择一个.(可以理解为IP报文的属性)
16位总长度(total length): IP数据报整体占多少个字节.
8位生存时间(Time To Live, TTL): 数据报到达目的主机的最大报文跳数.一般是64. 每次经过一个路由, TTL -= 1, 一直减到0还没到达, 那么就丢弃了. 这个字段主要是用来防止出现路由循环。
8位协议: 表示上层协议的类型(IP有效载荷中为UDP报文或TCP报文,这8位标识着IP报文在接收端的网络层解包之后将有效载荷应交给传输层的哪个协议)
16位头部校验和: 使用CRC进行校验, 来鉴别头部是否损坏.
32位源IP地址和32位目标IP地址: 表示发送端主机的IP地址和接收端主机IP地址.
选项字段(不定长, 最多40字节): 略
解决两个问题:
1. IP报文如何封装和解包:定长报头+自描述字段:有效载荷 = 16位总长度 - 4位首部长度 * 4
2. 如何向上交付(分用):IP报文解包之后,8位协议标识着有效载荷应该交给传输层的UDP还是TCP
网络编程时,服务端进程需要bind端口号和ip,ip就是在网络层的IP协议中工作的,而端口号工作在传输层。
IP数据报 - 数据分片
数据报为什么要分片?
数据链路层因为一些物理特征的原因,一般无法转发太大的数据。(具体原因在讲数据链路层时会讲)故链路层有一次可以转发到网络中的报文(这里的报文指的是IP报文,不过链路层也会对IP报文做进一步的封装(添加链路层协议的报头))大小的限制(如1500字节,MTU)。所以若网络层的IP报文为2500字节,超过了MTU,此时就需要进行数据报分片。
数据报分片是什么?
一个超过MTU的IP报文,拆分为多个小的,满足条件的IP报文(<=MTU)。
分片的行为是发送端网络层做的,分好之后传给下层数据链路层。同样组装的行为也是接收方网络层做的,因为接收方网络层需要组装好IP报文后,解包,给上方传输层一个完整数据段(UDP报文/TCP报文)。因此,IP报文分片和组装的行为,传输层是不知道的,不关心的。
为什么分片行为不在数据链路层进行?因为数据链路层是驱动层,涉及到了驱动的具体物理实现,可能不同厂商有不同实现,而所有操作系统要想进行网络传输,都需要TCP/IP协议,所以从这个角度来说,分片行为在IP层实现更好一些。
如何做到IP数据报分片?
IP协议报头中的第二行三个字段,就是用来进行分片和组装的:发送端需要保留分片的痕迹&&接收端需要根据这些字段进行组装。
16位标识(id): 唯一的标识主机发送的IP报文的序号. 如果IP报文被分片了, 那么每一个片里面的这个 id都是相同的。
3位标志字段: 第一位保留. 第二位置为1表示禁止分片, 此时若IP报文长度超过MTU, IP层就会丢弃此报文. 第三位表示"更多分片", 如果分片了, 最后一个分片置为0, 其他是1. 类似于一个结束标记。(若没分片,则肯定就是0,因为后面没有更多分片!)
13位分片偏移(framegament offset): 分片相对于原始IP报文开始处的偏移量. 其实就是在表示当前分片在原IP报文中处在哪个位置. 实际偏移的字节数是这个值 * 8得到的.
1. 分片行为并不是主流
2. 根据16位标识,不同报文,标识不同。相同报文的分片,标识相同。
3. 识别该IP报文是否被分片:被分片:更多分片为1 或者 更多分片为0&&13位片偏移不为0 不被分片:更多分片为0&&16位片偏移为0
4. 若IP报文被分片,则识别出哪个是开始,哪个是中间,哪个是结尾:开始:更多分片1,片偏移为0 中间:更多分片1,片偏移不为0 结尾:更多分片0,片偏移不为0。再根据偏移量将IP报文进行升序排序,根据偏移量 + 自身大小 = 下一个分片的偏移量。将所有IP报文的分片进行组装。若发现连接不上,则证明有IP报文分片丢包。
分片demo示例
IP报文长度 > MTU,则需要进行分片,分片之后,每一个分片都是一个独立的IP报文(更短)
可以理解为后面两个分片的报头是新增的,而后面两个分片的13位片偏移指的是这两个分片的有效载荷在原始IP报文中的偏移量。
并不推荐分片,能不分片则不分片。
因为分片,增加了丢包概率。若一个IP报文分为了4个分片,则任何一个分片丢包,都会导致整个IP报文无法组装,进而引发传输层重传等策略。
同时需要认识到,网络层的IP报文其实是IP报头+有效载荷,有效载荷为传输层报文,故,真正想解决分片问题,减少分片次数,还需要传输层来解决。因为网络层IP数据报的大小实际是由传输层数据段的大小决定的。
这就是为什么,TCP协议中,若对端主机的窗口大小为4096字节,此时发送端传输层会分几个报文发送,而不是一个,原因就是因为网络层有MTU限制,当传输层给网络层的TCP报文大小合规时,网络层才能不分片,从而减小丢包概率。
网段划分
前置了解
全球的每一台需要进行网络传输数据的主机或路由器等网络转发设备都有它自己的IP地址,这些IP地址是怎样的分布规律呢?
首先建立一个认知:全球的IP地址并非杂乱无章的,而是精心设计过的。
一种简单的理解方式:比如在国家层面上,将每个国家看作一个大型网段,则32位IP地址中,拿出8位作为国家层面的网络号,如中国为1,美国为2...而在一个国家内部,每个省作为一个网段划分区域,如再拿出5bit位,标识每个省的网络号的不同,比如山西00000001 00001......河南00000001 00011........而国家层面有国家层面的路由器,互相连接进行数据转发,而如果有一个IP报文是从国外向国内的某个省进行转发的,则国家层面路由器可以进行转发给国内的省层面的路由器。也就是说任何一个路由器一定连接了两个不同层面网段,一大一小,从而进行网络数据报转发。(可能)(上面这里只是理解,IP报文不是杂乱无章的,而是精心设计过的,实际上的划分可能并不是这样的,并且会复杂很多。)
谈论具体的IP地址网段划分方案之前,先说:
网络号和主机号
IP地址分为两个部分, 网络号和主机号
1. 网络号: 保证相互连接的两个网段具有不同的标识;
2. 主机号: 同一网段内, 主机之间具有相同的网络号, 但是必须有不同的主机号;
3. 不同的子网其实就是把网络号相同的主机放到一起.
4. 如果在子网中新增一台主机, 则这台主机的网络号和这个子网的网络号一致, 但是主机号必须不能和子网中的其他主机重复
通过合理设置主机号和网络号, 就可以保证在相互连接的网络中, 每台主机的IP地址都不相同
那么问题来了, 手动管理子网内的IP, 是一个相当麻烦的事情.
有一种技术叫做DHCP, 能够自动的给子网内新增主机节点分配IP地址, 避免了手动管理IP的不便. 一般的路由器都带有DHCP功能. 因此路由器也可以看做一个DHCP服务器.
为什么要把IP地址分为网络号和主机号?(作用)
网络号表征的是不同的区域(网段),不同网段的网络号不同。同时,网络号在根据目标IP的不断查找的过程中是不断变大的,且是收敛的。(如有一个目标IP,可以根据前8位确定在哪个国家,然后根据后5位确定在哪个省,这个过程中,网络号逐渐变大,范围逐渐收敛,且这个定位目标IP的过程是非常高效的)
网络号+主机号的作用:1. 便于定位 2. 提高查找效率
过去的一种划分网络号和主机号的方案,把所有的IP地址分为5类
这种划分方案的局限性很快显现出来,大多数组织都申请B类网络地址, 导致B类地址很快就分配完了, 而A类却浪费了大量地址; 例如, 申请了一个B类地址, 理论上一个子网内能允许6万5千多个主机. A类地址的子网内的主机数更多. 然而实际网络架设中, 不会存在一个子网内有这么多的情况. 因此大量的IP地址都被浪费掉了.
无类别域间路由CIDR
针对上方五类IP地址的规定造成大量IP地址浪费的情况,提出了新的划分方案, 称为CIDR(Classless Interdomain Routing)
引入一个额外的子网掩码(subnet mask)来区分网络号和主机号;
子网掩码也是一个32位的正整数. 通常用一串 "0" 来结尾;
将IP地址和子网掩码进行 "按位与" 操作, 得到的结果就是网络号;
网络号和主机号的划分与这个IP地址是A类、B类还是C类无关
比如,当有一个区域有300台主机,需要300个ip地址时,此时一个C类网络号可以容纳254个IP地址,此时必须申请B类,但是B类就会造成大量IP地址浪费。因此,子网掩码可以进一步划分这些分类后IP地址的子网络(ABC类),也就是主机号位数不再固定为8 16 24,此时一个网段内部(网络号固定)所能容纳的主机数就会更加灵活,故可以减少IP地址的浪费!(有类地址和无类地址是配合起来使用的,是不同级的。)
特殊的IP地址
将IP地址中的主机地址全部设为0, 就成为了网络号, 代表这个局域网;
将IP地址中的主机地址全部设为1, 就成为了广播地址, 用于给同一个链路中相互连接的所有主机发送数据包;
127.*的IP地址用于本机环回(loop back)测试,通常是127.0.0.1
IP地址的数量限制
IP地址不足的原因
IP地址(IPv4)是一个4字节32位的正整数. 那么一共只有 2的32次方 个IP地址, 大概是43亿左右. 而TCP/IP协议规定, 每个主机都需要有一个IP地址.
实际上, 由于一些特殊的IP地址的存在, 数量远不足43亿; 另外IP地址并非是按照主机台数来配置的, 而是每一个网卡都需要配置一个或多个IP地址.
CIDR在一定程度上缓解了IP地址不够用的问题(提高了利用率, 减少了浪费, 但是IP地址的绝对上限并没有增加), 仍然不够用.
这时候有三种方式来解决
1. 动态分配IP地址: 只给接入网络的设备分配IP地址. 因此同一个MAC地址的设备, 每次接入互联网中, 得到的IP地址不一定是相同的;
2. NAT技术(后面介绍);
3. IPv6: IPv6并不是IPv4的简单升级版. 这是互不相干的两个协议, 彼此并不兼容; IPv6用16字节128位来表示一个IP地址; 但是目前IPv6还没有普及
私有IP地址和公网IP地址
这里就是上方所讲的NAT技术的基础:私有IP地址。
如果一个组织内部组建局域网,IP地址只用于局域网内的通信,而不直接连到Internet上,理论上使用任意的IP地址都可以。这里的仅用于局域网内通信的IP地址就是私有IP地址。
RFC 1918规定了用于组建局域网的私有IP地址
1. 10.*,前8位是网络号,共16,777,216个地址
2. 172.16.到172.31.,前12位是网络号,共1,048,576个地址
3. 192.168.*,前16位是网络号,共65,536个地址
包含在这个范围中的, 都称为私有IP, 其余的则称为全局IP(或公网IP);
NAT
一个路由器可以配置两个IP地址, 一个是WAN口IP, 一个是LAN口IP(子网IP)(这就是我之前所说所理解的,一个路由器至少连接两个网段,层面上一大一小,当然,也有可能存在某种路由器仅用于同级转发)
路由器LAN口连接的主机, 都从属于当前这个路由器的子网中.
不同的路由器, 子网IP其实都是一样的(通常都是192.168.1.1). 子网内的主机IP地址不能重复. 但是子网之间的IP地址就可以重复了.(直接解决了IP地址不足的问题)
每一个家用路由器, 其实又作为运营商路由器的子网中的一个节点. 这样的运营商路由器可能会有很多级, 最外层的运营商路由器, WAN口IP就是一个公网IP了.
子网内的主机需要和外网进行通信时, 路由器将IP首部中的IP地址(源IP)进行替换(替换成WAN口IP), 这样逐级替换, 最终数据包中的源IP地址成为一个公网IP. 这种技术称为NAT(Network Address Translation,网络地址转换).
如果希望我们自己实现的服务器程序, 能够在公网上被访问到, 就需要把程序部署在一台具有外网IP的服务器上. 这样的服务器可以在阿里云/腾讯云上进行购买.(其实很简单,由上方可知,一般IP报文的目的IP地址不可以是一个私有IP,必须是一个公网IP)
1. 路由器天然的会构建局域网(子网)
2. 家用路由器:对内:自己构建的子网,对外:自己本身也是别人构建子网中的一个主机。
3. 决定了路由器至少要有两套地址:对内:LAN口IP,即自己构建的局域网中使用的私有IP,对外:WAN口IP,自己所在的上级子网给自己分配的IP。
4. 有些路由器的LAN口IP和WAN口IP都属于局域网IP,私有IP。而一定存在路由器的LAN口IP为局域网IP,WAN口IP为公网IP。这样的路由器就可以将收到的报文的源IP替换为公网IP,进行公网转发。
5. 路由器要做一个事情:将报文的源IP替换为路由器的WAN口IP。并且每经过一个运营商的内网路由器,都要做这个工作(公网路由不做)(内网路由器指的是该路由器的LAN口IP为一个局域网IP)
6. 源IP地址在不同内网,不同层级的网络节点中转发时被替换的技术:NAT
路由
在复杂的网络结构中, 找出一条通往终点的路线;
我们的IP数据报,由发送端主机发出,由路由器一跳一跳的转发,最终转发到目标主机处。这个过程中每一个路由器转发IP报文时都会依据目的IP地址,决定将此报文转发给接下来的哪一个路由器,或者是否已经可以直接转发给目标主机(此处的路由器即目标主机的入口路由器)。
路由的过程, 就是这样一跳一跳(Hop by Hop) "问路" 的过程. 所谓 "一跳" 就是数据链路层中的一个区间. 具体在以太网中指从源MAC地址到目的MAC地址之间的帧传输区间.
IP数据包的传输过程也和问路一样.
当IP数据包, 到达路由器时, 路由器会先查看目的IP;
路由器决定这个数据报是能直接发送给目标主机, 还是需要发送给下一个路由器;
依次反复, 一直到达目标IP地址;
那么如何判定当前这个数据报该发送到哪里呢?(接下来的哪一个路由器or直接发送给目标主机?) 这个就依靠每个节点内部维护一个路由表;
有关路由表的相关内容,略了~
IP没有提供设备转发的具体功能,IP提供的是转发的策略。也就是在复杂的网络环境中,IP网络层决定将此报文发送给下一跳的谁。
但是,如果数据报要想真正转发到下一跳,还要靠下一层:数据链路层。
局域网中数据报转发的问题,即一跳到一跳的过程,是由数据链路层完成的。(比如上方图中的路由器A转发给路由器B)