从 0-1 聊聊网络的演进

在上文中,我们讲述了访问网站的原理,即当我们解析到域名的IP地址时,需要与服务器建立连接。那么我们是如何根据 IP 找到这个服务器呢?

为了更好地解释这个问题,我们先从最简单的问题分析,将需要通信的设备简化为两台,只需用网线连接它们,这样就形成了最简单的网络。如下图所示:

设备A 和 设备B 进行了连接,他们就可以通信了。但是,如果现在我再加入一个设备C,整体的结构就变成了如下所示:

当设备A想要向设备B发送消息时,由于不知道目标端口,所以只能将消息发送到每个网口。这意味着设备C也会收到设备A的消息。那么设备C如何确定这个消息是否是针对自己的呢?这个问题暂时先不讨论,我们将在后面讨论。

第一层-物理层

通过上述分析,如果有三台设备,就需要每台设备连接两根网线,并且每个设备需要有两个网口(以此类推)。随着设备数量的增加,每个设备上的插口也会增多,这显然是不合适的。那么该如何解决呢?

解决方法有两种:

  1. 采用总线模式,如下图所示:

通过上图,我们可以使用一个总线将各个设备串联起来,这样每个设备就可以进行通信了。但是总线模式存在两个主要问题:

      1. 网络整体可靠性依赖于总线,总线故障会导致整个网络瘫痪。
      2. 设备之间的消息发送必须经过总线,导致冲突非常高。

因此,总线模式逐渐被淘汰。

  1. 添加一个特殊的设备进行转发,将请求转发到指定端口。

从上面的图上可以看出,我们加了一个特殊的设备,这个设备负责把收到的数据进行无脑的复制和发送到其他设备。 这样设备A就能和其他设备通信了,这个设备的名字就是 集线器 其主要功能是对接收到的信号进行再生整形放大,以扩大网络的传输距离。

在这个过程中,设备A发送消息1,经过集线器后,每个出口都会复制发送一份。

由于集线器没有任何逻辑,因此属于物理层。由于集线器将消息转发给每个设备,因此我们不知道消息发送给谁,只能在设备收到后自行判断。那么回到最初的问题,设备如何判断这个消息是否是针对自己的呢?这时我们需要在消息上加上一个特殊的设备ID,即MAC地址。

因此,我们的报文需要进行包装,增加发送方和接收方的MAC地址。整体的消息报文如下所示:

这时,当设备收到消息后,就可以拿到消息的目标MAC地址和自己的地址进行对比,如果不符合就直接丢弃。

第二层-数据链路层

当采用集线器的解决问题的时候,可能大家都感觉到问题了,主要问题有两个:

  1. 每次发送消息,都需要其他设备判断,带来整个设备群的设备性能降低
  2. 消息量复制n份,大大的浪费了资源。

随着设备的增多,集线器已经无法满足需求。我们需要更智能的设备,能够根据指定的MAC地址发送消息,这就是交换机。那么交换机是如何工作的呢?

在交换机的内部,维护着一个MAC地址对应端口号的地址表。收到消息后,交换机会根据MAC地址查询指定的端口,然后转发消息到该端口。

当然,在初始阶段,MAC地址表是空的。那么如何建立这个表呢?

当设备A发送消息给设备B时,交换机查询目标的MAC地址,发现没有查询到端口,因此会向每个端口都发送消息(盲目泛洪)。当所有设备收到消息后,都会向交换机发送反馈,只有B的反馈是正确的。因此,交换机就会在表中增加一条记录。

bb-bb-bb-bb-bb-bb 2

这样,下次再发送指定消息时,交换机就能直接找到相应的端口。到这里,我们已经建立了一个小型网络。

如果随着设备数量的增多,需要增加交换机的数量,那么如何在多个交换机之间建立路由表呢?

如下图:如果设备A想要发送消息给设备E,需要怎样进行转发呢?

对于这个问题,我们的处理方式是将交换机B中的设备都放到交换机A的MAC地址表中。具体表内容如下:

MAC地址 端口
aa-aa-aa-aa-aa-aa 1
bb-bb-bb-bb-bb-bb 2
cc-cc-cc-cc-cc-cc 3
ee-ee-ee-ee-ee-ee 4
ff-ff-ff-ff-ff-ff 4

这样,无论交换机B中有多少设备,交换机A都会将消息从4端口转发给交换机B,然后交换机B根据自己的地址表将消息转发到指定端口。

第三层-网络层

尽管交换机似乎解决了数据传输的问题,甚至还能够支持水平扩展,但随着设备数量的增加,MAC地址表会变得越来越庞大,特别是第一个交换机的MAC地址表。随着MAC表的增长,性能会逐渐降低。那么如何解决这个问题呢?

通过前面的分析,MAC地址表的增长主要是交换机的水平扩容后,需要把下一级的设备mac映射关系都放到第一级的交换机的地址表中,那如果有个设备,有单独的 MAC,我直接交给这个设备,由他在进行再分配,那这个问题就可以迎刃而解了,这个设备就是路由器,具体关系如下图:

通过上述分析,我们引入了路由器来解决交换机A中MAC地址表过大的问题。但是,新问题又出现了。MAC地址表如何配置才能够将数据经过路由器发送到设备E呢?为了弄清楚这个情况,我们需要梳理面临的问题。

  1. 首先需要知道,设备E和设备A不在同一个交换机集群内,因此需要路由器进行转发。(目前可以通过查询交换机表来解决)
  2. 如果交换机A接入多个路由器,需要知道转发到哪个路由器。(这个问题目前无法解决)
  3. 当转发给路由器时,路由器需要知道设备E在交换机B的集群内。(这个问题目前也无法处理)

为了解决以上问题,我们需要对消息体进行扩展,引入一个新的网络标识:IP地址。IP地址由4个8位整数组成:

11111111.11111111.11111111.11111111 对应的地址是:255.255.255.255

同样,我们的报文也需要加上源IP和目标IP。

那IP是如何解决上述的问题的呢?

在网络的最开始建立的时候,对每一个设备分配一个IP地址,这个地址属于软件层面,可以变动,这样也带来了整个网络集群的灵活性。

接下来,让我们逐个解决上述问题。

如何判断设备A和设备E不在同一个 交换机 集群内呢?

直观地看,192.168.0.100和192.168.1.100不在同一个网段上。那么计算机如何判断呢?

需要再引入两个概念:默认网关和子网掩码。这里先解释这两个概念及其作用:

  1. 默认 网关存在于每个设备上,通常是网络配置的一部分。当我们需要上网时,数据会首先发送到默认网关,通常情况下默认网关的地址就是我们家庭中的路由器地址(虽然不完全一致)。
  2. 子网掩码用于确定子网划分的范围。简单来说,IP地址由四个8位数字组成(实际上是32位),从后往前看,后面有几位0表示后续的IP可以分配,例如:
    1. 对于子网掩码255.255.255.0,对应网段为192.168.0.[0-255],可以分配256-2个IP地址(其中两个地址被保留为网络地址和广播地址)。
    2. 对于子网掩码255.255.0.0,对应网段为192.168.[0-255].[0-255],可以分配256×256-2个IP地址。

(这里减去2是因为其中两个地址被保留为网络地址和广播地址)

留给读者一个问题:为什么这里的IP以192.168.0.xxx开头?

计算机通过和子网掩码进行与运算来判断。如果结果一致,则说明两者在同一个网段。举个例子:

设备A: 192.168.0.100 & 255.255.255.0 = 192.168.0.0
设备B: 192.168.0.100 & 255.255.255.0 = 192.168.0.0
设备C: 192.168.1.100 & 255.255.255.0 = 192.168.1.0
所以在 默认网关是255.255.255.0的情况下:A和B 是一个网段,C不是。

因此,在默认网关是255.255.255.0的情况下,设备A和设备B在同一个网段,而设备C不在。我们在原来的基础上再加上子网掩码和默认网关:

同时为了表达方便,我们给路由器的 mac 地址为 ll-00-00-00-00-00,增加上网关和子网掩码,整个拓扑图如下:

由于A和B处于同一网段,它们可以直接通信。但是,A和E不在同一网段,因此不能直接互相通信。只能将数据发送给默认网关192.168.0.1(大多数情况下,默认网关的地址就是路由器的地址)。此时,路由器可以根据自己的路由表决定转发地址。

路由地址 子网掩码 下一跳
192.168.0.1~192.168.0.254 255.255.255.0 端口0直连
192.168.1.1~192.168.1.254 255.255.255.0 端口1直连

192.168.0.1~192.168.0.255 为了更简单表达这个方式,我们可以采用一种新的方式来表示:

192.168.0.0/24
 其中 24代表前前3个8位整数都是1 即:
 11111111.11111111.11111111.00000000
 255.255.255.0 
 即 192.168.0.0/24 可以代表 192.168.0.1~192.168.0.254
路由地址 子网掩码 端口
192.168.0.0/24 255.255.255.0 端口0直连
192.168.1.0/24 255.255.255.0 端口1直连

网络层 的路由

当路由器收到请求后,会将请求转发到端口1,即交换机B,此时交换机就获得了信息。

当交换机获得IP后,需要知道IP对应的MAC地址。这时该怎么办呢?

这就需要了解ARP(地址解析协议)和ARP缓存(ARP缓存的建立,此处先不展开)。格式如下:

IP 地址 MAC 地址
192.168.1.100 ee-ee-ee-ee-ee-ee

当拿到mac地址后就可以成功把数据转发了

先做一个总结

到这里了解了网络信息的流转的每一个步骤,我们先做一个总结,把报文的流程先梳理下:

第四层-运输层

到目前为止,我们已经大致了解了网络基本通信的原理,解决了网络连通的问题。接下来我们再继续探索。

在整个的网络流程中,归根到底是两个程序间的通信,我们可以思考一个问题,当我们收到数据时,如何知道这个数据是发给哪个程序的呢?

举例来说,当我们在上网的同时又在聊天,如何确保数据精准地分配给浏览器或 QQ 呢?

不同设备使用不是统一的操作系统,不同的操作系统(如 Windows、Linux、Mac OS)又使用不同格式的进程标识符。每个进程都需要发送数据,那么如何去隔离它们呢?

所以在运输层需要提供一个统一的标准来区分不同的进程,在 TCP/IP 运输层使用端口号来区分应用层的不同应用进程。

下图是我们常用端口

有了端口号,就可以区分不同进程对应的数据了。

第五层-应用层

总结前面的流程,我们似乎解决了网络传输中的所有问题了,采用路由器隔离网络,采用端口的区分了不同应用的数据等,那应用层又是用来解决什么问题呢?

应用层的作用,可以简单的理解成解决数据是什么的问题,比如:

我打开了一网页,服务端知道我访问了 80 端口,但是服务端不知道我访问的是哪个网页,这个时候就需要把网页路径传递过去。

那传递过去需要按什么格式呢?编码是什么?类型是啥等等,这些问题都是我们常见 HTTP 协议相关的内容。

所以应用层是和用户最直接接触和使用的层级,它负责提供各种协议的解析和渲染。

常见的协议有:

HTTP(超文本传输协议): 用于在客户端和服务器之间传输超文本(如网页),是万维网的基础协议。
HTTPS(安全超文本传输协议): 在HTTP的基础上添加了安全性支持,使用SSL/TLS协议对通信进行加密和身份验证。
FTP(文件传输协议): 用于在客户端和服务器之间传输文件,支持文件的上传、下载和管理。
SMTP(简单邮件传输协议): 用于在邮件服务器之间传输电子邮件。
POP3(邮局协议版本3): 用于从邮件服务器上下载电子邮件到本地客户端。
IMAP(互联网消息访问协议): 用于远程管理和检索电子邮件,支持在客户端和邮件服务器之间保持邮件状态同步。
DNS(域名系统): 用于将域名解析为对应的IP地址,以便在互联网上定位网络资源。
DHCP(动态主机配置协议): 用于自动分配IP地址、子网掩码、网关等网络配置信息给主机。
Telnet(远程终端协议): 用于远程登录到计算机系统,并在远程主机上执行命令和操作。
SSH(安全外壳协议): 在Telnet的基础上提供了加密和身份验证的安全远程登录方式。
SNMP(简单网络管理协议): 用于网络设备之间进行管理和监控,获取设备状态信息和执行管理操作。
NTP(网络时间协议): 用于同步网络中各个设备的时间,以确保时间的准确性和一致性。

总结:

这篇文章是从网络的五层模型,来探索网络的演进,我们从最简单的场景了解了网络演化的过程,并了解了每一个层的作用和对应的代表性的设备,最后在了解到最贴近我们日常使用的运输层和应用的作用和表现形式。

通过上面的总结,我们可以把整个的数据流程绘制如下: