本章主要讲解学习网络层的作用, 深入理解IP协议的基本原理
在网络体系中,每一层都是服务于对应的上下层的,网络层也是服务于上层的传输层和下层的数据链路层
网络层介于传输层和数据链路层之间,其主要作用是实现两个不同网络系统之间的数据透明传送,具体包括路由选择,拥塞控制和网际互连等(注:负责不同的网络之间(基于数据包的IP地址)尽力转发数据包,不负责丢包重传和接收顺序)
网络层在数据从数据链路层向传输层进行数据传输的通信中,起到构建一个中间通信子网的作用。不同网络有不同的网络层协议和地址规范,不同网络有不同的设计规范,属于不同的组织来管理,必须通过授权,并由专门的协议来负责网络间的通信
如果只是同一局域网内的各个计算机之间的通信,单靠物理层和数据链路层就可以建立通信链路完成用户间的数据通信,但要扩大应用范围,连接不同的局域子网,就需要借助网络层处理各个网络子网的协议,从而进行计算机的网络互连,所以网络层在 TCP/IP 协议体系中叫网际互连层
- 屏蔽网络差异,提供透明传输
网络层就是为了解决不同网络有不同的规范要求的差异问题,寻找一个不同网络间都能共同遵守的网络通信规范,以便不同网络间能相互识别,并接受对方的网络请求。也就是一个中转站的作用,两个毫无交集的网络通过这个中转站来建立交集
- 为网络间通信提供路由选择
路由选择是根据一定的原则和路由选择算法在多个结点的通信子网中选择一条到达目的节点的最佳路径的过程。确定路由选择的策略称为路由算法。在无连接的数据包服务中,网络节点要为每个数据包做出路由选择,即选择到达目的节点的最佳路线,而在面向连接的虚电路服务中,存在一条专门的逻辑线路,在建立连接时就已经确定了路有路径,无需额外选择
- 拥塞控制
拥塞控制是为了避免网络传输路径中数据的传输延迟或死锁。数据链路层中的流量控制功能,是针对数据链路中点对点传输速率的控制,这里的拥塞控制是针对在网络层传输路径中的端到端传输效率的控制。主要采用预约缓冲区、许可证和分组丢弃等方式
- 通常一个计算机网络就是一个管理边界,一般是属于一个特定的公司,有一个特定的管理者负责,所以在进行计算机网络互连时,要同时考虑两方面的问题:一是授权用户可以在不同网络间互访,共享双方的资源;另一方面又要保持各计算机网络管理原来的独立性
- 而不同用户之间进行通信,首先得知道彼此的地址,局域网内部的用户访问(物理层和数据链路层就可以构建一个局域网)是通过MAC地址进行,但不同网络之间进行访问需要网络层对应的一个网络地址来进行访问,每个网络都通过其网络地址即NSAP(网络服务访问点)来标识,网络中的每个节点都有一个NSAP。这个NSAP就是由对应网络所运行的网络层通信协议来定义的,在目前最常见的TCP/IP协议网络中,这个协议就是IP协议,对应的NSAP就是IP地址
- 在数据链路层中传输的是一个个以许多字节为单位的帧,在每个帧的帧头都有源节点的MAC地址和目的节点的MAC地址,局域网内部的寻址就是通过MAC地址进行的,而在网络层中传输的是数据报(Packet,也叫分组),一个数据报是一个数据帧经过网络层协议重封装后得到的,每个数据报的报头(IP头)都有源节点和目的节点的IP地址,网路间的寻址就是通过IP地址进行的
- 即网络通信只有两种情况:如果通信双方在同一个局域网内,可直接通过数据链路层进行相互通信,但因为主机其实也有网络层的路由功能,所以两台主机间进行网络通信时通常也是通过三层来进行的(IP协议则是IP地址寻址);如果通信双方在不同网络内,需要网络层中的网络地址进行寻址,即必须通过三层进行
- 主机: 配有IP地址, 但是不进行路由控制的设备
- 路由器: 即配有IP地址, 又能进行路由控制
- 节点: 主机和路由器的统称
- 4位版本号(version): 指定IP协议的版本, 对于IPv4来说, 就是4
- 4位头部长度(header length): IP头部的长度是多少个32bit, 也就是 length * 4 的字节数. 4bit表示最大的数字是15, 因此IP头部最大长度是60字节(表示范围20-60,注报头固定字段为20字节)
- 8位服务类型(Type Of Service): 3位优先权字段(已经弃用), 4位TOS字段, 和1位保留字段(必须置为0). 4位TOS分别表示: 最小延时, 最大吞吐量, 最高可靠性, 最小成本. 这四者相互冲突, 只能选择一个(注:对于ssh/telnet这样的应用程序, 最小延时比较重要; 对于ftp这样的程序, 最大吞吐量比较重要)
- 16位总长度(total length): IP数据报整体占多少个字节(IP报文最大为64KB)
- 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字节
- 当IP从底层获取到一个报文后,首先读取报文的前20个字节,并从中提取出4位的首部长度获得IP报头的大小(基本报头字段+选项字段)
- 首部长度之后就是有效载荷,再读取16位总长度,获得整个报文的大小,减去报头大小就是有效载荷的大小了
当IP从底层获取到一个报文后,提取8位协议从而知道应该将分离出来的有效载荷交付给上层的哪一个协议的
IP报头当中的32位源IP地址和32位目的IP地址,分别代表的就是该报文的发送端和接收端对应的IP地址
数据在不同网络传输的过程中会通过很多的路由器(连接不同网段),路由器具有网络层,会提取IP报头当中的目的IP地址,通过与路由表进行IP对比从而选择下一跳的网段,也就实现数据路由转发
当接收端收到了发送端发来的数据后,接收端可能也想要给发送端发送数据(或者进行应答),因此发送端在发送数据时除了需要指明该数据的目的IP地址,还需要指明该数据的源IP地址,也就是发送端的IP地址
- MAC帧作为数据链路层的协议,它会将IP传下来的数据封装成数据帧,然后发送到网络当中。但MAC帧携带的有效载荷的最大长度是有限制的,也就是说IP交给MAC帧的报文不能超过某个值,这个值就叫做最大传输单元(Maximum Transmission Unit,MTU),这个值的大小一般是1500字节
- 由于MAC帧无法发送大于1500字节的数据,因此IP层向下交付的数据的长度不能超过1500字节(IP的报头和有效载荷),如果超过了1500字节,那么就需要先在IP层对该数据进行分片,然后再将分片后的数据交给下层MAC帧进行发送
如果发送数据时在IP层进行了分片,那么当这些分片数据到达对端主机的IP层后就需要先进行组装,然后再将组装好的数据交付给上层传输层
实际在网络通信过程中不分片才是常态,因为数据分片会存在一些潜在的问题,比如分片可能会增加丢包的概率
数据的分片和组装发生在IP层,不仅源端主机可能会对数据进行分片,数据在路由过程中的路由器也可能对数据进行分片,因为不同网络的MTU是不一样的
- 对于分片后的多个报文,每一个报文的报头中的16位标识都是相同的,标识主机发送的同一个报文
- 同时在3位标志中的第三位“更多分片”字段中,最后一个分片报文设置为0以外(表示在这分片之后没有分片了),其余分片报文均设置为1(表示在这分片之后还有分片)
- 前面两个字段标识了同一报文、还有分片以及最后分片,为了避免分片的丢包,还需要13位片偏移字段进行校验是否丢了分片:该字段表示当前分片在原数据中的偏移位置,当前位置的偏移量+该分片的有效数据的长度=下一个分片的偏移量,而首个分片偏移为0,由此可以算出接下来的每一个分片的偏移位置,从而校验是否丢失了分片
注:实际偏移的字节数是这个值× 8 \times 8×8得到的,因此除了最后一个报文之外,其他报文的长度必须是8的整数倍,否则报文就不连续了
- 实际数据分片的根本原因在于传输层一次向下交付的数据太多了,导致IP无法直接将数据向下交给MAC帧,因此TCP作为传输控制协议需要控制一次向下交付数据不能超过阈值MSS(Maximum Segment Size最大报文段长度)
- MAC帧的有效载荷最大为MTU,TCP的有效载荷最大为MSS,由于TCP和IP常规情况下报头的长度都是20字节,因此一般情况下 MSS = MTU - 20 - 20,而MTU的值一般是1500字节,因此MSS的值一般就是1460字节,所以一般建议TCP将发送的数据控制在1460字节以内,此时就能够降低数据分片的可能性。之所以说是降低数据分片的可能性,是因为每个网络的链路层对应的MTU可能是不同的
- IP地址分为两个部分, 网络号和主机号
- 网络号: 保证相互连接的两个网段具有不同的标识
- 主机号: 同一网段内, 主机之间具有相同的网络号, 但是必须有不同的主机号
- 不同的子网其实就是把网络号相同的主机放到一起
- 如果在子网中新增一台主机, 则这台主机的网络号和这个子网的网络号一致, 但是主机号必须不能和子网中的其他主机重复
- 通过合理设置主机号和网络号, 就可以保证在相互连接的网络中, 每台主机的IP地址都不相同
- 手动管理子网内的IP, 而有一种技术叫做DHCP, 能够自动的给子网内新增主机节点分配IP地址, 避免了手动管理IP的不便
- 一般的路由器都带有DHCP功能. 因此路由器也可以看做一个DHCP服务器
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类却浪费了大量地址,然而实际网络架设中, 不会存在一个子网内有这么多的情况. 因此大量的IP地址都被浪费掉了,针对这种情况提出了新的划分方案, 称为CIDR(Classless Interdomain Routing)
引入一个额外的子网掩码(subnet mask)来区分网络号和主机号
子网掩码也是一个32位的正整数. 通常用一串 “0” 来结尾
将IP地址和子网掩码进行 “按位与” 操作, 得到的结果就是网络号
网络号和主机号的划分与这个IP地址是A类、B类还是C类无关
IP地址与子网掩码做与运算可以得到网络号, 主机号从全0到全1就是子网的地址范围
IP地址和子网掩码还有一种更简洁的表示方法:例如140.252.20.68/24,表示IP地址为140.252.20.68, 子网掩码的高24位是1,也就是255.255.255.0
- 将IP地址中的主机地址全部设为0, 就成为了网络号, 代表这个局域网;
- 将IP地址中的主机地址全部设为1, 就成为了广播地址, 用于给同一个链路中相互连接的所有主机发送数据包
- 127.*的IP地址用于本机环回(loop back)测试,通常是127.0.0.1
- IP地址(IPv4)是一个4字节32位的正整数. 那么一共只有 2的32次方 个IP地址, 大概是43亿左右. 而TCP/IP协议规定, 每个主机都需要有一个IP地址
- 实际上, 由于一些特殊的IP地址的存在, 数量远不足43亿,另外IP地址并非是按照主机台数来配置的, 而是每一个网卡都需要配置一个或多个IP地址
- CIDR在一定程度上缓解了IP地址不够用的问题(提高了利用率, 减少了浪费, 但是IP地址的绝对上限并没有增加), 仍然不是很够用
- 动态分配IP地址:只给接入网络的设备分配IP地址. 因此同一个MAC地址的设备, 每次接入互联网中, 得到的IP地址不一定是相同的
- NAT技术:能够让不同局域网当中同时存在两个相同的IP地址,NAT技术不仅能解决IP地址不足的问题,而且还能够有效地避免来自网络外部的攻击,隐藏并保护网络内部的计算机
- IPv6:IPv6并不是IPv4的简单升级版. 这是互不相干的两个协议, 彼此并不兼容; IPv6用16字节128位来表示一个IP地址,目前IPv6还没有普及
如果一个组织内部组建局域网,IP地址只用于局域网内的通信,而不直接连到Internet上,理论上使用任意的IP地址都可以,但是RFC1918规定了用于组建局域网的私有IP地址
- 10.* ,前8位是网络号,共16,777,216个地址
- 172.16.到172.31.,前12位是网络号,共1,048,576个地址
- 192.168.*,前16位是网络号,共65,536个地址
包含在这个范围中的, 都成为私有IP, 其余的则称为全局IP(或公网IP)
- 一个路由器可以配置两个IP地址, 一个是WAN口IP, 一个是LAN口IP(子网IP)
- 路由器LAN口连接的主机, 都从属于当前这个路由器的子网中
- 不同的路由器, 子网IP其实都是一样的(通常都是192.168.1.1). 子网内的主机IP地址不能重复. 但是不同子网的IP地址就可以重复了
- 每一个家用路由器, 其实又作为运营商路由器的子网中的一个节点. 这样的运营商路由器可能会有很多级,最外层的运营商路由器, WAN口IP就是一个公网IP了
- 子网内的主机需要和外网进行通信时, 路由器将IP首部中的IP地址进行替换(替换成WAN口IP), 这样逐级替换, 最终数据包中的IP地址成为一个公网IP. 这种技术称为NAT(Network Address Translation,网络地址转换)
- 如果希望我们自己实现的服务器程序, 能够在公网上被访问到, 就需要把程序部署在一台具有外网IP的服务器上. 这样的服务器可以在阿里云/腾讯云上进行购买
- 实际网络通信的基础设施都是运营商搭建的,我们访问服务器的数据并不是直接发送到了对应的服务器,而是需要经过运营商建设的各种基站以及各种路由器,最终数据才能到达对应的服务器
- 用户上网的数据首先必须经过运营商的相关网络设备,然后才能发送到互联网公司对应的服务器,而所谓的网段划分、子网划分等工作实际都是运营商做的
NAT(Network Address Translator,网络地址转换)是用于在本地网络中使用私有地址,在连接互联网时转而使用全局 IP 地址的技术,NAT实际上是为解决IPv4地址短缺而开发的技术
- 以 10.0.0.10 的主机与 163.221.120.9 的主机进行通信为例讲解 NAT 的工作机制。利用 NAT,途中的 NAT 路由器将发送源地址从 10.0.0.10 转换为全局的 IP 地址(202.244.174.37)再发送数据
- 反之,当响应数据从 163.221.120.9 发送过来时,目标地址(202.244.174.37)先被转换成私有 IP 地址 10.0.0.10 以后再被转发
网络被分为私网和公网两个部分,NAT网关设置在私网到公网的路由出口位置,双向流量必须都要经过NAT网关
NAT 路由器在两个访问方向上完成两次地址的转换或翻译,出方向做源信息替换,入方向做目的信息替换
网络访问只能先由私网侧发起,公网无法主动访问私网主机(不存在替换会话,无法找到对应的私网主机)
NAT 路由器的存在对通信双方是保持透明的
NAT 路由器为了实现双向翻译的功能,需要维护一张关联表,把会话的信息保存下来
NAT 有 3 中类型:静态NAT,动态NAT,端口复用NAPT
- 静态NAT
内部本地地址一对一转换成内部全局地址,相当内部本地的每一台PC都绑定了一个全局地址。一般用于在内网中对外提供服务的服务器
- 动态NAT
在内部本地地址转换的时候,在地址池中选择一个空闲的,没有正在被使用的地址,来进行转换,一般选择的是在地址池定义中排在前面的地址,当数据传输或者访问完成时就会放回地址池中,以供内部本地的其他主机使用,但是,如果这个地址正在被使用的时候,是不能被另外的主机拿来进行地址转换的
- 端口复用NAPT
面对私网内部数量庞大的主机,如果NAT只进行IP地址的简单替换,就会产生一个问题:当有多个内部主机去访问同一个服务器时,从返回的信息不足以区分响应应该转发到哪个内部主机。此时,需要 NAT 设备根据传输层信息或其他上层协议去区分不同的会话,并且可能要对上层协议的标识进行转换,比如 TCP 或 UDP 端口号。这样 NAT 网关就可以将不同的内部连接访问映射到同一公网IP的不同传输层端口,通过这种方式实现公网IP的复用和解复用。这种方式也被称为端口转换PAT、NAPT或IP伪装,但更多时候直接被称为NAT,因为它是最典型的一种应用模式
以私网 10.0.0.10 和 10.0.0.11 的主机与外网 163.221.120.9 的主机进行通信为例讲解 NAPT 的工作机制
- 主机 163.221.120.9 的端口号是 80,私网中有 2 个客户端 10.0.0.10 和 10.0.0.11 同时进行通信,并且这 2 个客户端的本地端口都是 1025。此时,仅仅转换 IP 地址为全局地址 202.244.174.37 ,会令转换后的数字完全一致
- 因此,为了区分这 2 个会话,只要将 10.0.0.11 的端口号转换为 1026 就可以解决问题。NAPT 路由器通过生成转换表,就可以正确地转换地址跟端口的组合,使客户端A、B能同时与服务器之间进行通信
- 利用端口号的唯一性实现了公网 IP 到私网 IP 的转换,理论上最多可以让 65535 台主机共用一个公网 IP 地址
节省合法的公有 IP 地址(最大的优点)
当网络发生变化时,避免重新编址
对外隐藏内部地址,增加网络安全性(网络访问只能先由私网侧发起,公网无法主动访问私网主机)
无法从NAT 的外部向内部服务器建立连接(NAT穿越)
转换表的生成和转换操作都会产生一定的开销
通信过程中一旦 NAT 遇到异常需重新启动时,所有的 TCP 连接都将被重置。即使备置两台 NAT 做容灾备份,TCP 连接还是会被断开
- 数据的发送和转发就是在复杂的网络结构中, 找出一条通往终点的路线
- 路由的过程, 就是这样一跳一跳(Hop by Hop) “问路” 的过程
- 数据在路由的过程中,实际就是一跳一跳(Hop by Hop)“问路”的过程。所谓“一跳”就是数据链路层中的一个区间,具体在以太网中指从源MAC地址到目的MAC地址之间的帧传输区间
- IP数据包的传输过程也和问路一样
- 当IP数据包, 到达路由器时, 路由器会先查看目的IP
- 路由器决定这个数据包是能直接发送给目标主机, 还是需要发送给下一个路由器
- 依次反复, 一直到达目标IP地址
- 而判定当前这个数据包该发送位置就是依靠每个节点内部维护一个路由表
- 得知该数据下一跳应该跳到哪一个子网,转发给下一个子网
- 没有发现匹配的子网,此时路由器会将该数据转发给默认路由
- 目标网络就是当前所在的网络,此时路由器就会将该数据转给当前网络中对应的主机
每个路由器内部会维护一个路由表,我们可以通过route命令查看云服务器上对应的路由表
- Flags中,U标志表示此条目有效(可以禁用某些条目)G标志表示此条目的下一跳地址是某个路由器的地址,没有G标志的条目表示目的网络地址是与本机接口直接相连的网络,不必经路由器转发
- 当IP数据包到达路由器时,路由器就会用该数据的目的IP地址,依次与路由表中的子网掩码 Genmask进行“按位与”操作,然后将结果与子网掩码对应的目的网络地址Destination进行比对,如果匹配则说明该数据包下一跳就应该跳去这个子网,此时就会将该数据包通过对应的发送接口Iface发出(Iface代表的是发送接口)
- 如果将该数据包的目的IP地址与子网掩码进行“按位与”后,没有找到匹配的目的网络地址,此时路由器就会将这个数据包发送到默认路由,也就是路由表中目标网络地址中的default。可以看到默认路由对应的Flags是UG,实际就是将该数据转给了另一台路由器,让该数据在另一台路由器继续进行路由
- 静态路由:是指由网络管理员手工配置路由信息
- 动态路由:是指路由器能够通过算法自动建立自己的路由表,并且能够根据实际情况进行调整