网络层 -- IP协议
在传输层TCP协议提供了可靠传输的策略。但是我们还需要提供数据跨网络传输的能力,这就是IP协议的工作。
要将数据从A主机跨网络运输到B主机就必须清除源主机和目标主机,这就需要对每台主机进行标识。再打个比方,我们旅游去某个地方的时候,都是先定位目标城市,再定位城市中的具体地点。目标城市就像网络,具体地点则是该片网络中的某个具体主机。即数据传输应该是先去往目标网络,再找到目标主机。所以 ip = 目标网络 + 目标主机。IP协议就提供了在复杂的网络环境中确定一个合适的路径的能力。
基本概念
主机:配有IP地址,但是不进行路由控制的设备
路由器:配有IP地址,又能进行路由控制
节点:主机和路由控制的统称
协议头格式
- 4位版本号(version):指定IP协议的版本,对于IPv4来说就是4
- 4位头部长度(header length):IP头部的长度是多少个32bit,也就是length*4的字节数.4bit表示最大的数字是15,因此IP头部最大长度是60字节
- 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位协议:表示将IP报文交给哪个上层协议,即上层协议的类型
- 16位头部校验和:使用CRC进行校验,来鉴别头部是否损坏
- 32位源地址和32位目标地址:表示发送端和接收端
- 选项字段(不定长,最多40字节)
有了上述字段的认识,可得出IP协议是通过固定长度(20字节)和自描述字段(首部长度和总长度)来将报头和有效载荷分离的,同时也有8位协议字段标识将有效载荷交给哪个上层协议具体过程:
- IP报文首部的长度至少20字节,先读取20字节,接着通过首部长度字段确定首部长度
- 读取完整的首部信息
- 16位总长度出去首部长度就是有效载荷信息
关于8位生存时间:当报文无法到达目标主机(目标主机已经离线/环路路由),该报文就成了一个废弃的游离报文,如果持续在网络中继续发送无疑会消耗网络资源,因此设置TTL代表报文到达目的地的最大跳数,报文没经过一次路由TTL就会减一,当减到0时该报文会被彻底丢弃。
IP分片
为什么要分片
实际上,在一台主机中,报文也并不是通过网络层直接发出去的,而是交给了自己的下一层协议(数据链路层)。数据链路层要求一次不能发送过大的报文,因此,也要求上层不能给数据链路层交付过大的报文。如果报文过大,IP协议会对报文进行分片。
分片的过程
IP报文的长度不能超过数据链路层协议定义的最大传输单元MTU,一般为1500字节。
现在假设一个原始IP数据包(总长度为2000 字节,头部固定为20字节)要通过一个MTU为1000字节的网络。若分片过程中所有分片的头部均为20字节,则分片结果如下:
原始数据长度 = 2000字节 - 20字节 = 1980字节
每个分片最大数据长度 = 1000字节 - 20字节 = 980字节
分片数量 = 1980字节 / 980字节 ≈ 3
第二个分片的片偏移 = 2 * 980 / 8 = 245,更多分片为1
第三个分片是最后一个分片,更多分片为0
(这里数据不是很恰当,实际上分片相对于原始数据的偏移量必须是8的整数倍否则片偏移不是整数)
分片组装
- IP报文中给出了源IP地址,根据这一点区分不同主机的数据
- 如果IP报文中片偏移为0且更多分片为0,则该报文未经过分片,是独立报文不需要组装
- 否则需要收集该标识的不同分片,首先读取片偏移为0的报文中的16位总长度,然后依次计算出下一分片的片偏移,直到更多分片为0为止
分片报文丢包
首先我们需要知道收到的报文是否经过分片,分片报文满足的条件是“片偏移不为0或者更多分片被设置为1”,但是若片偏移为0且更多分片为0,则该报文是独立报文。
如果丢失了第一个分片报文——找不到该报文标识中片偏移为0的分片报文
如果丢失了最后一个分片报文——找不到该报文标识更多分片为1的分片报文
如果丢失了中间的报文——计算出下一分片报文的片偏移后找不到对应的分片报文
但是需要注意,一般情况下不建议对IP报文进行分片!
如果IP报文进行了分片,接收端只有收到全部的分片报文并将其组装起来时才认为该可靠地收到了该报文标识的报文。如果其中一个分片报文丢失,接收端无法将报文成功组装起来,此时接收端会将所有收到的分片报文丢弃,而传输层则因为收不到对方应答而进行超时重传。
而不同层之间的协议都是独立的,传输层的TCP并不知道报文进行了分片,收到报文丢失的信息之后回对整个报文都进行重传。分片的报文丢失的概率相对于未分片的报文也更大,因此不建议对IP报文进行分片。
网段划分
IP地址分为两个部分,网络号和主机号:
- 网络号:保证相互连接的两个网段具有不同的标识;
- 主机号:同一网段内,主机之间具有相同的网络号,但是必须有不同的主机号
其中,
- 路由器本质也是一个子网的主机,也要配置ip地址
- 路由器一定至少连接2个子网,路由器也就相当于同时在2个子网(路由器可以配置多个ip,我们可以认为路由器有多张网卡)
- 路由器一般是一个子网中的第一台设备,一般ip地址是:网络号.1
- 路由器功能不仅是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
- 例如申请了一个B类地址, 理论上一个子网内能允许6万5千多个主机. A类地址的子网内的主机数更多
- 然而实际网络架设中, 不会存在一个子网内有这么多的情况. 因此大量的IP地址都被浪费掉了
- 引入一个额外的子网掩码来区分网络号和主机号;
- 子网掩码也是一个32位的正整数. 通常用一串 "0" 来结尾;
- 将IP地址和子网掩码进行 "按位与" 操作, 得到的结果就是网络号;
- 网络号和主机号的划分与这个IP地址是A类、B类还是C类无关;
特殊的IP地址
- 将IP地址中的主机地址全部设为0就成为了网络号,代表这个局域网
- 将IP地址中的主机地址全部设为1就成为了广播地址,用于给同一个链路中互相连接的所有主机发送数据包
- 127.*的IP地址用于本机环回(loop back)测试,通常是127.0.0.1
IP地址的数量限制
- 动态分配IP地址:只给接入网络的设备分配IP地址.因此同一个MAC地址的设备,每次接入互联网中得到的IP地址不一定是相同的
- NAT技术
- IPv6:IPv6不是IPv4的简单升级版,是互不相干的两个协议,彼此不兼容;IPv6用16字节128位来表示一个IP地址;但目前还没有普及IPv6
私有IP地址和公网IP地址
- 10.*,前8位是网络号,共16777216个地址
- 172.16.到172.31.,前12位是网络号,共1048576个地址
- 192.168.*,前16位是网络号,共65536个地址
据我个人观察192.168.的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(网络地址转换)
- 如果希望我们自己实现的服务器程序能够在公网上被访问到,就需要把程序部署在一台具有外网IP的服务器上
关于NAT技术。为什么要替换IP地址——假设我们给某一服务器发送请求,服务器要响应请求发回数据时,不可能通过私有IP来定位目标主机,因为私有IP可能出现重复,只能是公网IP。所以我们在发送数据时需要逐级替换IP地址。
路由
在复杂的网络结构中,找出一条通往终点的路线。路由的过程实际就是一跳一挑“问路”的过程,假如我们要从武汉的欢乐谷去深圳的欢乐谷,我们需要先到达“目的网络”北京,但是可能要先经过长沙、广州,路由器就是负责告诉数据怎么走的“导游”,告诉数据先到达长沙,再到达广州,再从广州到达深圳,接下来才是去深圳的欢乐谷。
所谓“一跳”就是数据链路层的一个区间.具体在以太网中指从源MAC地址到目的MAC地址之间的帧传输区间。
IP数据包的传输过程也和问路一样
- 当IP数据包到达路由器时,路由器会先查看目的IP
- 路由器决定这个数据包是否能直接发送给目标主机,还是需要发送给下一个路由器
- 依次反复,一直到达目的IP地址
至于如何判定当前数据包该发送到哪里要依靠每个节点内部维护一个路由表:
主机A要发送数据到主机B,查询路由表得知要先发送数据给路由器A,但主机A并不知道发送到路由器A之后数据的发送路径,也不需要知道,数据到达路由器A之后再查询路由器A的路由表到达下一跳,依次重复这个过程知道到达主机B。
- 如果目的IP命中了路由表直接转发即可
- 当目的地址与路由表中其它行都不匹配时,就按缺省路由条目规定的接口发送到下一跳地址
路由表可以使用route命令查看:
可以看到当前主机有一个网络接口连接到10.1.8.0/22网络;
路由表的Destination是目的网络地址,Genmask是子网掩码,GateWay是下一跳地址,Iface是发送接口,Flags中的U标志表示此条目有效(可以禁用某些条目),G标志表示此条目的下一跳地址是某个路由器的地址,没有G标志的条目表示目的网络是与本机接口直接相连的网络,不必经由路由器转发。
路由表生成算法:
路由表可以由网络管理员手动维护(静态路由),也可以通过一些算法自动生成(动态路由),相关的生成算法有:距离向量算法、LS算法、Dijkstra算法等