admin管理员组

文章数量:1544558

作者:@小萌新
专栏:@网络
作者简介:大二学生 希望能和大家一起进步
本篇博客简介:详细介绍下IP协议

IP协议

  • IP协议
    • 基本概念
    • ip协议格式
    • 分片和组装
    • 网段划分
    • 特殊的IP地址
    • IP地址数量限制
    • 私网IP和公网IP
    • 路由
    • 路由表生成算法

IP协议

IP协议全称为“网际互连协议(Internet Protocol)” IP协议是TCP/IP体系中的网络层协议

基本概念

我们上面回答了IP协议是什么 接下来应该回答的问题应该是IP协议有什么用

我们之前再讲网络基础的时候讲过一个快递的故事 再这里再简单重复下

假设用户现在购买了一款洗面奶产品 现在让卖家开始发货

卖家讲货物添加了快递单等信息之后就交给了一家快递公司

该快递公司经过路线研究之后选择了 上海 - 福建 - 江苏这条路

其中为什么会选择这条路而不是其他路线就是网络层决定的

映射到网络通信中 网络层要解决的问题就是 将数据从一台主机送到另一台主机 也就是数据的路由

再学过了传输层和应用层之后大家可以思考下传输层和应用层有什么作用

传输层保证的是快递在运输过程中的安全到达 如果说快递在中途丢了 传输层要重新发送

应用层则是保证如何使用这个洗面奶

所以说从上面的例子中我们就知道了 传输层的作用是选择路线

我们在上一篇博客TCP协议中说过 网络中的数据传输其实就是从一端主机的发送缓冲区将数据拷贝到另一端的接收缓冲区 这其实是不准确的 因为我们当时讲解的时候忽略了传输层的下两层也就是网络层和数据链路层的作用

与学习传输层一样的是 为了方便大家学习理解 我们在学习网络层的时候也有意忽略数据链路层的作用

保证数据可靠的从一端到另一端的前提

这个小节实际上讲解的是为什么网络层能够完成它的作用

我们可以想象 保证数据可靠的从一端到另一端 首先我们的前提肯定是发送方要有发送的数据的能力吧 如果发送方连这个能力都没有就不用谈发送数据了

网络在大部分情况下是畅通的 但是有时候也可能出错 也就是说我们将数据从一台主机发送到另外一台主机是有可能发送成功的 但是也可能会有失败的情况 也就是说我们网络层传输数据是大概率成功的 但是也会有失败的情况

那么我们怎么才能够让网络层传输数据变为百分百成功呢?

很简单 如果网络层传输出问题了那就重新发 直到成功为止 这就是保证网络层传输数据百分百成功的方法

也就是说网络层并不能保证数据传输的可靠性 这需要传输层提供一定的可靠性策略来完成(比如说超时重传机制和快重传机制等)

我们总结下:

  • 网络层解决的是 将数据从一台主机送到另一台主机 因为网络层解决的是主机到主机的问题
  • 传输层解决的是进程到进程之间的问题

IP层是怎么做的 – 路径选择

数据在进行网络传输的时候一般都是跨网络的 而我们的路由器就是连接各个网络的硬件设备 因此在数据传输的时候要经过多个路由器

TCP/IP协议是全球几十亿乃至上百亿台主机都在使用的一点点的误差都会造成很大的影响 TCP/IP协议必须要做到高效

网络层也属于TCP/IP协议 所以说我们网络层也必须要做到高效

所以说当我们确定了出发地点和目的地之后我们就需要找最短路径了

确定了数据路由的目的地之后 数据就可以在网络中进行路由了 但是我们的数据本身是不认路的 所以说需要不停的找人问路 而找的问路的人其实就是路由器

网络中的路由是认识路的 它们将自己的认路经验都填写到了路由表中 所以说路由器可以通过查询特定的路由表去找到最短路径

因此数据在路由的时候会不断通过路由器来进行路径选择 以此来一步步靠近目标网络和主机

概念介绍:

  • 主机: 配有IP地址 但是不进行路由控制的设备 但是发展到今天 现在的主机几乎都能够进行路由控制了
  • 路由: 配有IP地址 并可以进行路由控制的设备 但是现在今天的路由器甚至可以有某些应用层的功能了
  • 节点: 主机和路由器的统称

ip协议格式

ip协议格式如下:

  • 4位版本号:用来表示IP协议的版本 IP4/IP6
  • 4位首部长度:表示IP报头的长度 以四字节为单位
  • 8位服务类型:其中包括3位优先权字段(已弃用) 4位TOS 1位保留字段(必须设置为0) 其中四位TOS分别表示最小延时 最大吞吐量 最高可靠性 最小成本 (只能选一个) 不用的应用程序要求不同 其中像ssh/telnet之类的程序要求最小延时 ftp之类的应用程序要求最大吞吐量
  • 16位总长度:IP报文的长度(报头+有效载荷) 用于将各个IP报文进行分离
  • 16位标识:唯一标识主机发送的报文 如果报文进行了分片则每个分片的16为标识都是相同的
  • 3位标识字段: 第一位字段表示保留 暂时没有规定该字段的意义 第二位字段表示禁止分片 如果该报文长度超过MTU则直接丢弃 第三位表示更多分片 如果该位为0 则表示后面没有分片了 如果该位为1 则表示后面还有分片
  • 13位片偏移:分片相对于原数据的初始位置的偏移 表示该分片在原数据中的偏移位置 实际偏移的字节数=该值*8 所以说除了最后一个报文之外 其他所有报文的长度都要是8的整数倍
  • 8位生存时间(TTL):数据到达目的地的最大报文跳数 一般设置为64 每经过一个路由 TTL-1 如果一直减到0还没有到达则该报文丢弃 这个字段主要用来防止报文在路由中循环
  • 8位协议:表示上层协议的类型(一般为UDP或者是TCP)
  • 16位首部检验和:使用CRC进行校验 来鉴别数据包的首部是否损坏 但不鉴别数据部分
  • 32位源IP地址和32位目的IP地址:表示发送端和接收端的IP地址
  • 选项:不定长字段 最多是40字节(由4位首部长度可计算)

IP报文在Linux内核中实际上就是一个位段结构体 当我们需要使用数据封装一个IP报头的时候 我们实际上就是使用该类型定义一个变量 并且填充该变量的各个属性字段 最后将这个IP报头封装到数据的首部 我们这个时候就完成了IP的封装

IP报文如何将报头和有效载荷分离

IP的报文中给我们提供了两个字段 16位总长度和4位首部长度

其中16位总长度是报文的总大小 4位置首部长度*4是基本报头+选项的大小

基本报头的大小是20个字节

所以说我们得到一个IP报文之后 首先读取前20个字节就是IP报文的基本报头

之后读取4位首部长度*4 - 20个字节就是选项的长度

最后我们再读取16位总长度-4位首部长度*4 就是我们的有效载荷了

需要注意的是我们的选项是不一定存在的 如果选项不存在的话那么我们IP报文的报头就是20字节

IP如何决定将有效载荷交给上层的哪个协议

基于IP协议的传输层协议不止一个 所以说我们要告诉IP将有效载荷交给传输层的哪个协议

我们在IP的基本报头中能够读取到一个8位协议的字段 该字段存在的意义就是IP应该将有效载荷交给上层的哪个协议

该字段是发送方的IP层从传输层获取到字段后填充的 比如说上层是TCP协议传输过来的数据 那么该字段就会填写TCP协议对应的协议号

32位源IP和32位目的IP

32位源IP地址和32位目的IP地址表示的是发送端和接收端的主机IP

数据在网络传输的过程中会遇到一个个的路由器 这些路由器会帮助网络中的数据进行路由转发 使得网络中的数据慢慢趋近于目标主机 路由器在帮助数据进行路由转发的时候会提取IP报文当中的32位目的IP地址并和自己的路由表进行对照 选择一条最短路径

当接收端收到了发送端发来的数据之后 它有可能会对发送端进行回复 因为我们在IP报文中也需要知名发送端的源IP 并且就算接收端不想给发送端发送数据 如果传输层是TCP协议的话 接收端也要给发送端进行应答 所以说32位源IP地址这一项是必要的

再理解socket编程:

我们在进行socket编程的时候 需要绑定目的主机的IP地址和需要交付的端口号

其中IP地址这一项是网络层IP协议使用的 它通过该目的IP让数据在网络中进行路由 不断的问路靠近目的地址

端口号这一项是传输层协议使用的 它告诉传输层的协议应该将有效数据交付给上层的哪一个进程

当我们发送数据的时候我们不需要填写源IP地址和源端口号 因为在底层操作系统给帮我们自动填写

8位生存时间

在网络传输的过程中 可能由于某些原因导致报文无法到达目标主机 如果我们没有TTL的话该报文可能会在网络中不停的游离 如果说网络中存在大量这样的报文的话 网络的资源就会被大量的浪费 所以说我们设置8位生存时间是必要的

8位生存时间(TTL)代表的是数据到达目的地的最大报文跳数 一般设置为64 每经过一个路由 TTL-1 如果一直减到0还没有到达目的主机该报文则会被丢弃 该字段解决的就是上面大量报文在网络中游离的问题

分片和组装

数据链路层解决的问题

数据链路层的最常见协议是MAC帧 它解决的问题是将数据从一个节点传输到和自己相邻的下一个节点

那么IP层和数据链路层之间有什么联系呢?

IP能跨网络的将数据从一台主机发送到另一台主机 而数据在进行跨网络传输的时候需要通过一个个的路由器进行路由转发 才能到达目的主机

如下图主机B想要发送一个数据给主机C 那么主机B要先将数据交给路由F 路由F要将数据交给路由G … … 最终由路由D将该数据交给主机C


其中这一跳一跳的过程就是数据链路层的工作 而IP层的工作就是找到一个最短路径

最大传输单元MTU

我们在前面介绍了 数据在路由器之间一跳一跳的过程是MAC帧实现的 MAC帧携带数据有限制 叫做最大的传输单元MTU 一般是1500字节

MAC帧作为数据链路层的协议他会将IP层传下来的数据封装成数据帧 之后再网络中传输

我们再Linux下可以使用对应的ifconfig命令来查看MTU

我们在第一行就可以看到 mtu确实是1500 (一般都是这个数字)

分片和组装

在MTU为1500字节的情况下 如果说要传输的数据大于1500字节 就需要在IP层进行分片 然后将分片后的数据交给下层的MAC帧

如果说IP数据在发送端进行了分片 那么在到达接收端网络层之后就要进行组装 组装完毕之后再将数据打包传递给下一层

下面是一些注意点:

  • 在网络通信中数据的分片不是常态 大部分数据是不分片的 因为数据分片会增加数据在网络中传输时丢包的概率
  • 数据在经过路由器的时候也有可能会进行分片 我们在上面讲过数据是在网络层进行分片和封装的 实际上不光我们的发送端和接收端有网络层 我们的路由器也是网络层设备 而在网络传输的过程中每个局域网之间的MTU可能不同 所以会在路由器发生切分
  • 分片数据的组装只会发生在目的端的IP层
  • 在网络传输的过程中 可能有些报文没有传输层的报头 因为我们是在网络层将数据进行切分的 在将数据进行切分之后我们只能够加上IP的报头 传输层的报头只会出现在第一个分片中

数据的分片和组装都是在IP层

数据的分片和组装都是在IP层完成的 IP层上层传输层下层数据链路层都是不关心的

对于传输层来说 它需要保证的是数据传输的可靠性 如果数据在传输中出现了丢包乱序等情况传输层会进行重传

  • 在发送端 传输层将数据交给网络层之后 它不关心网络层会不会进行分片 它只关心这个数据有没有送达到对端
  • 在接收端 传输层从网络层获取数据 它也不关心这个数据是否进行了组装

对于数据链路层来说 它只需要保证数据从一个节点传输到另一个节点

  • 在发送端 网络层将数据交给MAC帧之后 MAC帧并不知道这个数据是否被分片 它只知道自己一次最多能发送MTU个字节的有效数据 只要不超过这个有效数据就可以
  • 在接收端 MAC帧向上交付给网络层的时候 它也不关心数据是否要被重组

下面我们会详细的介绍下分片和组装的过程

报文的分片和组装

我们假设现在IP层要发送4500个字节的数据 那么它应该如何将数据交付给数据链路层 更准确的说 它应该如何分片呢? (默认MTU为1500的情况下)

我们这里要明确一个概念 数据链路层的有效载荷就是IP整个报文(报头+数据)

我们假设所有分片的IP报头都不携带选项字段 即所有报头的大小都是20字节

那么我们每个IP报文所能携带的有效数据是1480个字节 我们可以按照下列方式将IP报文进行分片

分片报文总字节数IP报头字节数数据字节数
11500201480
21500201480
31500201480
4802060

需要注意的是 我们不能简单的使用4500 / 1500 = 3 来计算出分片的报文数 还要考虑IP报头的影响

分片分完传输到对端之后是要被重新组装起来的 所以说我们需要一些数据来支持对端进行组装操作 在报文中 16位标识 3位标志 13位片偏移都是用来做这个工作的

  • 16位标识:唯一标识主机发送的报文 如果报文进行了分片则每个分片的16为标识都是相同的
  • 3位标识字段: 第一位字段表示保留 暂时没有规定该字段的意义 第二位字段表示禁止分片 如果该报文长度超过MTU则直接丢弃 第三位表示更多分片 如果该位为0 则表示后面没有分片了 如果该位为1 则表示后面还有分片
  • 13位片偏移:分片相对于原数据的初始位置的偏移 表示该分片在原数据中的偏移位置 实际偏移的字节数=该值*8 所以说除了最后一个报文之外 其他所有报文的长度都要是8的整数倍

我们通过这三个字段就能够将所有分片的报文重新排序并组装起来 大概过程如下

  • 首先通过16位标识找到所有的同属于P报文分片
  • 接着我们通过确认13位片偏移最大的分片的三位标识字段是否为 000 来确认这是否为最后的报文
  • 然后我们将这些报文去掉报头 使用13位片偏移的大小进行排序
  • 最后我们就得到一个组装好的IP报文了

不过需要注意的是 我们上面讨论的是报文全部到达中间无丢包的情况 如果丢包了那么传输层就会进行重传

关于13位片偏移它们的大小是数据字节数除以8 比如说我们当前的有效字节数是1480 那么13位数据偏移的大小就是185

分片报文丢包的问题

分片报文在传输的过程中有可能会存在丢包的问题 但是我们的接收端有能力去分别该分片是否丢包

首先我们的接收端能够分辨一个报文是完整的报文还是被分片的报文

如果说一个报文的3位标识字段是000 并且 13位偏移量是0 那么这个报文就是完整未被分片的 其余情况都证明该报文被分片了

接下来就是我们知道了一个报文是分片报文 接收了若干分片报文之后我们如何分辨它是否丢包

其实思路也很简单 首先确定第一位(偏移量为0)和最后一位(3为标识字段为0)是否被丢包

如果没有我们就开始按照13位片偏移量进行排序 如果中间某个位置缺失了一段数据那就是丢包了 如果没有那就没有丢包

我们不建议让报文分片

我们不建议让报文分片 如果有大量的报文进行分片十分影响传输的效率

假设我们在传输层的时候每次传输大量的数据 那么IP层就要将该数据进行分片 分成大量单独的报文进行传输 如果说我们在中途丢失了某一个报文 那么传输层就要将所有的报文进行重发 所以说这是很影响传输效率的

也就是说 虽然我们传输层不关心网络层的分片问题 但是网络层的分片问题却会对传输层造成影响

所以说我们要尽可能的避免分片

如何尽可能的避免分片呢?

分片的直接原因就是传输层一次给网络层太多的数据了 所以说想要避免分片 传输层每次给予网络层少量的数据就可以了

实际上我们TCP/IP协议也给出了控制传输数据的机制

  • TCP作为传输协议 它需要控制每次向下交付的数据不能超过某一阈值 这个阈值叫做MSS(Maximum Segment Size,最大报文段长度)
  • 双方在建立TCP连接的时候 除了协商窗口大小之外 还会协商出一个后序通信时每个报文段所能承担的最大报文长度MSS

MAC帧的有效载荷最大为MTU TCP的有效载荷最大为MSS 由于TCP和IP常规情况下报头的长度都是20字节 因此一般情况下 MSS = MTU - 20 - 20 而MTU的值一般是1500字节 因此MSS的值一般就是1460字节

但是我们使用MSS机制并不能完全避免报文分片 因为每个网络的数据链路层对应的MTU是不同的 有可能在一个局域网的MTU特别小 此时就必须要进行分片了

网段划分

网段是指一个计算机网络中使用同一物理层设备能够直接通讯的那一部分

要了解网段的划分我们必须要先了解IP地址的构成和DHCP协议

ip地址的构成

ip地址由网络号和主机号两部分构成

  • 网络号:保证相互连接的两个网段具有不同的标识
  • 主机号:同一网段内 主机具有相同的网络号 但是必须有不同的主机号

我们可以在ip地址的后面加上一个 / 并且在 / 的后面加上一个数字 这就表示从头数到第几位为止属于网络标识

比如说在下图中 路由器连接了两个网段 对于网络标识来说 同一网段内主机的网络标识是相同的 不同网段内主机的网络标识是不同的

  • 不同的子网其实就是将网络号相同的主机放到一起
  • 如果在子网中新增一台主机 那么该主机的网络号要和子网网络号相同 但是主机号要不同

DHCP协议

实现手动管理IP是一个很麻烦的事情 所以说我们一般使用DHCP协议来进行管理

当子网中有新增主机的时候需要给主机分配一个新的IP地址 而当子网中有主机断开网络的时候有需要将其IP地址进行回收 如果都是我们自己手动操作就会很麻烦 所以说我们要使用DHCP协议

DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)技术是一个基于UDP的应用层协议

它的主要作用就是集中地址管理、分配IP地址 使网络环境中的主机动态获得IP地址、Gateway地址、DNS服务器地址等信息 并能够提升地址的使用率

我们一般的路由器都有DHCP功能 所以说路由器也可以看作是一个DHCP服务器

当我们连接WiFi时需要输入密码 本质就是因为路由器需要验证你的账号和密码 如果验证通过 那么路由器就会给你动态分配了一个IP地址 然后你就可以基于这个IP地址进行各种上网动作了

IP查找步骤

IP的查找步骤是先找网络再找主机 这样子是很高效的一个做法

因为我们在找一个主机的过程实际上就是在排除其他主机的过程 如果我们一开始就找的是IP地址(或者是主机号) 这样子的排除效率就太慢了 相当于我们要把网络中所有的主机都要排除一遍

但是如果我们一开始查找的时候不是查找主机 而是查找网络号 那么在查找的过程中的每次查找就能排除掉一大片的主机 这样子就能大大的提高搜索的效率

所以说 为了提高我们的IP搜索效率 我们要进行网段划分

网段划分

那么网段是怎么划分的呢?

在过去我们提出过一种划分网络号和主机的方案 就是把所有的IP地址分为五类 如下图

所以说 各类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

当我们要判断一个IP地址属于哪个类时 我们只需要遍历这个IP的前五个比特位 找出第一个出现0值的比特位就能够分辨这个IP属于哪一类地址

子网划分

我们上面分配网络地址的方式存在很大局限性

比如说一些学校 公司 实验室等组织想要申请自己的局域网而申请IP地址 但是因为A类的地址的网络号理论上只有2的7次方个 所以说更多的组织选择申请B类地址 这样子操作就会造成两个问题

  1. B类地址不够用
  2. 理论上B类地址的主机最多能有65536台 但是大多数局域网中都没有这么多台主机

综上 这种分配方式在事实上就造成了大量的浪费

于是乎为了解决这个问题 我们又提出了新的划分方案 称为CIDR

CIDR协议

CIDR协议的做法是

  • 在原有的五类网络的基础上继续进行子网划分 这也就意味着需要借用主机号当中的若干位来充当网络号 此时为了区分IP地址中的网络号和主机号 于是引入了子网掩码(subnet mask)的概念
  • 每一个子网都有自己的子网掩码 子网掩码实际就是一个32位的正整数 通常用一串“0”来结尾
  • 将IP地址与当前网络的子网掩码进行“按位与”操作 就能够得到当前所在网络的网络号

此时一个网络就被更细粒度的划分成了一个个更小的子网 通过不断的子网划分 子网中IP地址对应的主机号就越来越短 因此子网当中可用IP地址的个数也就越来越少 这也就避免了IP地址被大量浪费的情况

  • 比如在某一子网中将IP地址的前24位作为网络号 那么该网络对应的子网掩码的32个比特位中的前24位就为1 剩下的8个比特位为0 将其用点分十机制表示就是255.255.255.0
  • 假设该子网当中有一台主机对应的IP地址是192.168.128.10 那么将这个IP地址与该网络对应的子网掩码进行“按位与”操作后得到的就是192.168.128.0 这就是这个子网对应的网络号
  • 实际在用子网掩码与子网当中主机的IP地址进行“按位与”操作时 本质就是保留了主机IP地址中前24个比特位的原貌 将剩下的8个比特位的值清0了而已 也就是将主机号清0了 所以“按位与”后的结果就是该网络对应的网络号

需要注意的是 子网划分不是只能进行一次 我们可以在划分出来的子网的基础上继续进行子网划分

因此一个数据在路由的时候 随着数据不断路由进入更小的子网 其网络号的位数是在不断变化的

准确来说其网络号的位数是在不断增加的 这也就意味着IP地址当中的主机号的位数在不断减少 最终当数据路由到达目标主机所在的网络时 就可以在该网络当中找到对应的目标主机并将数据交给该主机 此时该数据的路由也就结束了

特殊的IP地址

并不是所有的IP都能成为主机的IP 有些IP地址本身就是具有特殊用途的

  • 将IP地址中的主机地址全部设为0 就成为了网络号 代表这个局域网
  • 将IP地址中的主机地址全部设为1 就成为了广播地址 用于给同一个链路中相互连接的所有主机发送数据包
  • 127.*的IP地址用于本机环回(loop back)测试 通常是127.0.0.1

也就是说 IP地址中主机号为全0的代表的是当前局域网的网络号 IP地址中主机号为全1的代表的是广播地址 这两个IP地址都是不能作为主机的IP地址的

本机环回基本原理

本机环回会将数据贯穿网络协议栈 但最终并不会将数据发送到网络当中 相当于本机环回时不会将数据写到网卡上面

本机环回的目的就是将数据自顶向下贯穿协议栈 进行一次数据封装的过程的过程,然后再自底向上贯穿协议栈 进行一次数据的解包和分用 用于测试本地的网络功能是否正常

本机环回的基本原理:

  • 当数据到达IP层需要继续向下交付时 如果是环回程序 那么IP输出函数会将该数据放入到IP输入队列当中 然后再由IP输入函数读取上去
  • 而IP输入函数将数据读取上去的本应该是链路层交付上来的数据 因此该数据后续就会被当作从网络中读取上来的数据看待 各层协议会对该数据依次进行解包和分用
  • 如果不是环回程序的话 那么接下来就会判断该数据对应的目的IP地址是否为广播或多播地址 或者目的IP地址是否与本主机的IP地址相同 如果是则也会将该数据放入到IP输入队列当中 等待IP输入函数将其读走
  • 只有判断程序不是环回程序 并且也不是广播或多播 或发给本主机的数据后 才会用ARP获取该数据目的主机的以太网地址并进行后续数据发送的操作

IP地址数量限制

我们知道 IP地址(IPV4)是一个4字节32位的二进制数字 也就是说我们的IP地址一共有将近43亿个地址 根据TCP/IP协议规定每一个主机都需要有一个IP地址

但是现在全球已经有70亿的人口了 随着科技的发展 我们的手机 电脑 乃至智能手表等都需要一个IP地址 此外IP地址也不是每台主机只需要一个的 一个主机可能需要多个IP地址并且路由也需要IP地址 以及一些特殊的IP地址不能使用

所以说43亿个IP地址其实早就不够用了 因此我们在提出CIDR协议对于已经划分好的五类网络进行网段划分

但是实际上我们的CIDR协议只能够减少IP地址的浪费 并不能扩充IP地址 所以说实际上目前的IP地址依然是不够用的

如何解决IP地址不足的问题

解决IP地址不足有以下几个方式

  • 动态分配IP地址:只给接入网络的设备分配IP地址 因此同一个MAC地址的设备每次接入互联网中 得到的IP地址不一定是相同的 避免了IP地址强绑定于某一台设备
  • NAT技术:能够让不同局域网当中同时存在两个相同的IP地址 NAT技术不仅能解决IP地址不足的问题 而且还能够有效地避免来自网络外部的攻击 隐藏并保护网络内部的计算机
  • IPv6:IPv6用16字节128位来表示一个IP地址 能够大大缓解IP地址不足的问题 但IPv6并不是IPv4的简单升级版 它们是互不相干的两个协议 彼此并不兼容 因此目前IPv6还没有普及

私网IP和公网IP

私网IP地址的种类

如果一个组织内部组建局域网 IP地址只用于局域网内的通信 而不直接连到Internet上 理论上使用任意的IP地址都可以 但是RFC 1918规定了用于组建局域网的私有IP地址

  • 10.*,前8位是网络号,共16,777,216个地址
  • 172.16.到172.31.,前12位是网络号,共1,048,576个地址
  • 192.168.*,前16位是网络号,共65,536个地址

包含在这个范围中的 都称为私网IP 其余的则称为公网IP(或全局IP)

我们连接云服务器时 连接的这个IP地址就是云服务器的公网IP地址

我们可以通过ifconfig命令来查看我们这台机器的私网IP eth0代表的就是我这台机器的网络接口 可以看到我的私网IP地址是10.0.8.3 符合上面建立私网IP的限制

我们这里使用的是腾讯云服务器 公网IP是该台服务器在公网中的ip 而私网ip则是该云服务器在腾讯内部的私网ip

我们享受的是互联网厂商的服务 为什么给运营商交钱

因为基础设置是运营商建设的

实际网络通信的基础设施都是运营商搭建的 我们访问服务器的数据并不是直接发送到了对应的服务器 而是需要经过运营商建设的各种基站以及各种路由器 最终数据才能到达对应的服务器

因为运营商为我们提供了通信的基础设施 所以我们交网费实际就相当于购买入网许可一样 没有运营商提供的这些基础设施 就不会诞生所谓的互联网公司 因为互联网公司是诞生在网络通信基础之上的

也就是说其实用户接收和发送的所有数据都要经过运营商修建的基础设置 我们上网的所有数据都是可以被运营商查到的 事实上网段划分 子网划分等工作也是运营商做的

数据是如何发送到服务器的

数据是通过路由器发送到服务器的

路由器是连接两个或多个网络的硬件设备 在路由器上有两种网络接口 分别是LAN口和WAN口:

  • LAN口(Local Area Network):表示连接本地网络的端口 主要与家庭网络中的交换机、集线器或PC相连
  • WAN口(Wide Area Network):表示连接广域网的端口 一般指互联网

我们将LAN口的IP地址叫做LAN口IP 也叫做子网IP 将WAN口的IP地址叫做WAN口IPO 也叫做外网IP

我们使用的电脑、家用路由器、运营商路由器、广域网以及我们要访问的服务器之间的关系大致如下:

  • 不同的路由器,子网IP其实都是一样的(通常都是192.168.1.1) 子网内的主机IP地址不能重复 但是子网之间的IP地址就可以重复了
  • 每一个家用路由器 其实又作为运营商路由器的子网中的一个节点 这样的运营商路由器可能会有很多级 最外层的运营商路由器的WAN口IP就是一个公网IP了
  • 如果希望我们自己实现的服务器程序 能够在公网上被访问到 就需要把程序部署在一台具有外网IP的服务器上 这样的服务器可以在阿里云/腾讯云上进行购买

由于私网IP不能出现在公网当中 因此子网内的主机在和外网进行通信时 路由器会不断将数据包IP首部中的源IP地址替换成路由器的WAN口IP 这样逐级替换 最终数据包中的源IP地址成为一个公网IP 这种技术成为NAT(Network Address Translation,网络地址转换)

为什么私网IP不能出现在公网当中?

  • 不同的局域网中主机的IP地址可能是相同的 所以私网IP无法唯一标识一台主机 因此不能让私网IP出现在公网上 因为IP地址要能唯一标识公网上的一台主机
  • 由于IP地址不足的原因 我们不能让主机直接使用公网IP而让主机使用私网IP 因为私网IP可以重复也就意味着我们可以在不同的局域网使用相同的IP地址 缓解了IP的不足

两个局域网当中的主机不能不跨公网进行通信

理论上是不可行的

因为两台主机在进行通信的时候必须要知道另一台主机的IP地址 即是说我们得到了对方的IP地址 这两个IP地址也可能会是一样的 有可能主机将数据发送给了自己(本地回环)

所以说两个局域网要进行通信不经过公网基本上是不可能的 我们在和别人聊天的时候也不是将数据直接从一个局域网发送到了另外一个局域网 而是先将数据发送到了公网 然后再由路由器将数据发送到了另外一个局域网

但实际确实存在一些技术能够使数据包在发送过程中不进行公网IP的替换 而将数据正确送到目标主机,这种技术叫做内网穿透 也叫做NAT穿透

路由

数据“问路”的过程

数据在路由的过程中 实际就是一跳一跳(Hop by Hop)“问路”的过程 所谓“一跳”就是数据链路层中的一个区间 具体在以太网中指从源MAC地址到目的MAC地址之间的帧传输区间

IP数据包的传输过程中会遇到很多路由器 这些路由器会帮助数据包进行路由转发 每当数据包遇到一个路由器后 对应路由器都会查看该数据的目的IP地址 并告知该数据下一跳应该往哪跳

路由器的查找结果可能有以下三种:

  • 路由器经过路由表查询后 得知该数据下一跳应该跳到哪一个子网
  • 路由器经过路由表查询后 没有发现匹配的子网 此时路由器会将该数据转发给默认路由
  • 路由器经过路由表查询后 得知该数据的目标网络就是当前所在的网络 此时路由器就会将该数据转给当前网络中对应的主机

路由表查询的具体过程

每个路由器内部会维护一个路由表 我们可以通过route命令查看云服务器上对应的路由表

  • Destination代表的是目的网络地址
  • Gateway代表的是下一跳地址
  • Genmask代表的是子网掩码
  • Flags中 U标志表示此条目有效(可以禁用某些条目)G标志表示此条目的下一跳地址是某个路由器的地址 没有G标志的条目表示目的网络地址是与本机接口直接相连的网络 不必经路由器转发
  • Iface代表的是发送接口

当IP数据包到达路由器时 路由器就会用该数据的目的IP地址 依次与路由表中的子网掩码 Genmask进行“按位与”操作 然后将结果与子网掩码对应的目的网络地址Destination进行比对 如果匹配则说明该数据包下一跳就应该跳去这个子网 此时就会将该数据包通过对应的发送接口Iface发出

如果将该数据包的目的IP地址与子网掩码进行“按位与”后 没有找到匹配的目的网络地址 此时路由器就会将这个数据包发送到默认路由 也就是路由表中目标网络地址中的default 可以看到默认路由对应的Flags是UG 实际就是将该数据转给了另一台路由器 让该数据在另一台路由器继续进行路由

数据包不断经过路由器路由后 最终就能到达目标主机所在的目标网络 此时就不再根据该数据包目的IP地址当中的网络号进行路由了 而是根据目的IP地址当中的主机号进行路由 最终根据该数据包对应的主机号就能将数据发送给目标主机了

路由表生成算法

路由可分为静态路由和动态路由:

  • 静态路由:是指由网络管理员手工配置路由信息
  • 动态路由:是指路由器能够通过算法自动建立自己的路由表 并且能够根据实际情况进行调整

路由表相关生成算法:距离向量算法、LS算法、Dijkstra算法等

本文标签: 协议Networkip