跳至主要內容

基础 - 输入网址到网页显示发生了什么


数据封装解封装

在数据传输过程中要遵循对等层次通信,每一层都与另一方对等层次进行通信 网络层-网络层、数据链路层-数据链路层。 而这些对等通信,并非直接进行的。而是由下层逐层封装来完成对等层交换数据,这就是我们数据的封装。 而解封装,就是上层需要与下层进行通信,于是逐层解封装至目标层进行通信。 这里的上下层就是指的网络参考模型的层次。

上面可能说的有点复杂不易于理解,可以记住下面这句话:数据发送时,从上至下逐层封装;数据接收时,从下至上逐层解封装;只有拆除外层封装,才能看到内层封装。

数据封装过程:

  1. 数据从应用层发出,进入传输层
  2. 传输层会为数据打上TCP or UDP头部,里面包含了数据的源端口、目的端口,到这层的时候,数据已经被封装成了数据段
  3. 数据段从传输层发出,进入网络层,在网络层,会为数据段打上一个IP头部里面包含了数据段的源IP 、目的IP,这时候在网络层的数据段被封装成了数据包
  4. 数据包从网络层发出,进入数据链路层,在数据链路层会封装一个以太网帧头部里面包含了二层数据源MAC、目的MAC地址,这时候数据包已经被封装成了数据帧
  5. 最后,数据帧从数据链路层发出,进入物理层,在这里将由物理层将帧转换为01011二进制形式的比特流在网络进行传输。

注意,数据的封装、解封装都是逐层进行的,不会出现跃层通信

数据的解封装同封装原理一样,只不过顺序进行了颠倒,从物理层的二进制数据流开始逐层解封装直至应用层

假设应用层程序是HTTP,过程如下:

简单的网络模型
简单的网络模型

应用层 - HTTP

应用层其实就是将数据封装成最后的HTTP报文,能够通过TCP的协议号看到上层是HTTP这个应用程序。

而浏览器首先做的第一步工作就是要对 URL 进行解析,从而生成发送给 Web 服务器的请求信息。

先看看一条长长的 URL 里的各个元素的代表什么,见下图:

URL 解析
URL 解析

所以 URL 实际上是请求服务器里的文件资源。

当没有路径名时,就代表访问根目录下事先设置的默认文件,也就是 /index.html 或者 /default.html 这些文件,这样就不会发生混乱了。

URL 进行解析之后,浏览器确定了 Web 服务器和文件名,接下来就是根据这些信息来生成 HTTP 请求消息了。

HTTP 的消息格式
HTTP 的消息格式

真实地址查询 - DNS

通过浏览器解析 URL 并生成 HTTP 消息后,需要委托操作系统将消息发送给 Web 服务器。而web服务器一般都不在本机,需要跨网络传输(即使在本机,也需要经过本机的网络IO)。

从上面的数据封装知道,其实当前只有一个HTTP的消息,而目前只知道Web 服务器的域名地址,但并不知道web服务器在哪里,因此就要查询服务器域名对应的 IP 地址

既然都要找ip地址,那为什么不用ip地址来标识web服务器呢,还要域名呢?因为ip地址难记,比如访问baidu,能知道直接访问www.baidu.com就行,而不是还要记那一串的数字。如果迁移到ipv6,那要记的ipv6地址就更长了。

所以,有一种服务器就专门保存了 Web 服务器域名与 IP 的对应关系,它就是 DNS 服务器。

域名的层级关系

DNS 中的域名都是用句点来分隔的,比如 www.server.com,这里的句点代表了不同层次之间的界限

在域名中,越靠右的位置表示其层级越高

毕竟域名是外国人发明,所以思维和中国人相反,比如说一个城市地点的时候,外国喜欢从小到大的方式顺序说起(如 XX 街道 XX 区 XX 市 XX 省),而中国则喜欢从大到小的顺序(如 XX 省 XX 市 XX 区 XX 街道)。

实际上域名最后还有一个点,比如 www.server.com.,这个最后的一个点代表根域名。

也就是,. 根域是在最顶层,它的下一层就是 .com 顶级域,再下面是 server.com

所以域名的层级关系类似一个树状结构:

  • 根 DNS 服务器(.)
  • 顶级域 DNS 服务器(.com)
  • 权威 DNS 服务器(server.com
DNS 树状结构
DNS 树状结构

根域的 DNS 服务器信息保存在互联网中所有的 DNS 服务器中。这样一来,任何 DNS 服务器就都可以找到并访问根域 DNS 服务器了。因此,客户端只要能够找到任意一台 DNS 服务器,就可以通过它找到根域 DNS 服务器,然后再一路顺藤摸瓜找到位于下层的某台目标 DNS 服务器。

域名解析的工作流程

  1. 客户端首先会发出一个 DNS 请求,问 www.server.com 的 IP 是啥,并发给本地 DNS 服务器(如windows电脑中 填写的 DNS 服务器地址)。
  2. 本地域名服务器收到客户端的请求后,如果缓存里的表格能找到 www.server.com,则它直接返回 IP 地址。如果没有,本地 DNS 会去问它的根域名服务器:“老大, 能告诉我 www.server.com 的 IP 地址吗?” 根域名服务器是最高层次的,它不直接用于域名解析,但能指明一条道路。
  3. 根 DNS 收到来自本地 DNS 的请求后,发现后置是 .com,说:“www.server.com 这个域名归 .com 区域管理”,我给你 .com 顶级域名服务器地址给你,你去问问它吧。”
  4. 本地 DNS 收到顶级域名服务器的地址后,发起请求问“老二, 你能告诉我 www.server.com 的 IP 地址吗?”
  5. 顶级域名服务器说:“我给你负责 www.server.com 区域的权威 DNS 服务器的地址,你去问它应该能问到”。
  6. 本地 DNS 于是转向问权威 DNS 服务器:“老三,www.server.com对应的IP是啥呀?” server.com 的权威 DNS 服务器,它是域名解析结果的原出处。为啥叫权威呢?就是我的域名我做主。
  7. 权威 DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS。
  8. 本地 DNS 再将 IP 地址返回客户端,客户端和目标建立连接。

由上也可以看出,客户端到本地DNS服务器的过程是递归查询:因为客户端只发一次请求,要求对方给出最终结果。而本地DNS服务器的过程是迭代查询:客户端发出一次请求,对方如果没有授权回答,它就会返回一个能解答这个查询的其它名称服务器列表,客户端会再向返回的列表中发出请求,直到找到最终负责所查域名的名称服务器,从它得到最终结果。

至此,完成了 DNS 的解析过程。现在总结一下,整个过程我画成了一个图。

域名解析的工作流程
域名解析的工作流程

那是不是每次解析域名都要经过那么多的步骤呢?当然不是了,浏览器会先看自身有没有对这个域名的缓存,如果有,就直接返回,如果没有,就去问操作系统,操作系统也会去看自己的缓存,如果有,就直接返回,如果没有,再去 hosts 文件看,也没有,才会去问「本地 DNS 服务器」。

指南好帮手 - 协议栈

通过 DNS 获取到 IP 后,就可以把 HTTP 的传输工作交给操作系统中的协议栈

协议栈的内部分为几个部分,分别承担不同的工作。上下关系是有一定的规则的,上面的部分会向下面的部分委托工作,下面的部分收到委托的工作并执行。这个其实就是数据的封装过程了。

应用程序(浏览器)通过调用 Socket 库,来委托协议栈工作。协议栈的上半部分有两块,分别是负责收发数据的 TCP 和 UDP 协议,这两个传输协议会接受应用层的委托执行收发数据的操作。

协议栈的下面一半是用 IP 协议控制网络包收发操作,在互联网上传数据时,数据会被切分成一块块的网络包,而将网络包发送给对方的操作就是由 IP 负责的。

此外 IP 中还包括 ICMP 协议和 ARP 协议。

  • ICMP 用于告知网络包传送过程中产生的错误以及各种控制信息。
  • ARP 用于根据 IP 地址查询相应的以太网 MAC 地址。

IP 下面的网卡驱动程序负责控制网卡硬件,而最下面的网卡则负责完成实际的收发操作,也就是对网线中的信号执行发送和接收操作。

可靠传输 - TCP

可以先看一下 TCP报头详解

在数据封装中,在传输层主要是数据 源端口号目标端口号,源端口号标识自己发出的端口号,目标端口号标识要发给哪个应用程序。这里是要发送HTTP数据,是基于 TCP 协议传输的,因此目标端口号是80,源端口号一般是大于1023 小于65535的 随机数。

当然TCP报文中的其它字段的数据都需要封装,为了满足不同的要求,如确认号,目的是确认发出去对方是否有收到。窗口大小,TCP 可以做流量控制

当然了,TCP 传输数据之前,要先三次握手建立连接,三次握手目的是保证双方都有发送和接收的能力

TCP 的连接状态

TCP 的连接状态查看,在 Linux 可以通过 netstat -napt 命令查看。

TCP 连接状态查看
TCP 连接状态查看

TCP 分割数据

如果 HTTP 请求消息比较长,超过了 MSS 的长度,这时 TCP 就需要把 HTTP 的数据拆解成一块块的数据发送,而不是一次性发送所有数据。

MTU 与 MSS
MTU 与 MSS
  • MTU:一个网络包的最大长度,以太网中一般为 1500 字节。
  • MSS:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度。

数据会被以 MSS 的长度为单位进行拆分,拆分出来的每一块数据都会被放进单独的网络包中。也就是在每个被拆分的数据加上 TCP 头信息,然后交给 IP 模块来发送数据。

数据包分割
数据包分割

TCP 报文生成

TCP 协议里面会有两个端口,一个是浏览器监听的端口(通常是随机生成的),一个是 Web 服务器监听的端口(HTTP 默认端口号是 80, HTTPS 默认端口号是 443)。

在双方建立了连接后,TCP 报文中的数据部分就是存放 HTTP 头部 + 数据,组装好 TCP 报文之后,就需交给下面的网络层处理。

远程定位 - IP

TCP 模块在执行连接、收发、断开等各阶段操作时,都需要委托 IP 模块将数据封装成网络包发送给通信对象。

IP报文头部详解看这篇文章

在 IP 协议里面需要有源地址 IP目标地址 IP

  • 源地址IP,即是客户端输出的 IP 地址;
  • 目标地址,即通过 DNS 域名解析得到的 Web 服务器 IP。

因为 HTTP 是经过 TCP 传输的,所以在 IP 包头的协议号,要填写为 06(十六进制),表示协议为 TCP。

假设客户端有多个网卡,就会有多个 IP 地址,那 IP 头部的源地址应该选择哪个 IP 呢?当存在多个网卡时,在填写源地址 IP 时,就需要判断到底应该填写哪个地址。这个判断相当于在多块网卡中判断应该使用哪个一块网卡来发送包。这个时候就需要根据路由表规则,来判断哪一个网卡作为源地址 IP。

而在DNS查询阶段,就已经知道了目标IP地址,有了源IP和目的IP,就可以将IP报文封装好了。

两点传输 - MAC

生成了 IP 头部之后,接下来网络包还需要在 IP 头部的前面加上 MAC 头部。在 MAC 包头里需要发送方 MAC 地址接收方目标 MAC 地址,用于两点之间的传输

MAC头部详解

一般在 TCP/IP 通信里,MAC 包头的协议类型只使用:

  • 0800 : IP 协议
  • 0806 : ARP 协议

MAC 发送方和接收方如何确认?

  • 发送方的 MAC 地址获取就比较简单了,MAC 地址是在网卡生产时写入到 ROM 里的,只要将这个值读取出来写入到 MAC 头部就可以了。
  • 接收方的 MAC 地址就是要发送的对方的 MAC 地址。

所以先得搞清楚应该把包发给谁,这个只要查一下路由表就知道了。在路由表中找到相匹配的条目,然后把包发给 路由表中下一跳中的 IP 地址就可以了。

知道了要发给谁,但还是不知道对方的MAC地址,因此 ARP 协议就登场了,来找到下一跳的MAC地址。

ARP 协议会在以太网中以广播的形式,发出ARP解析包,后续操作系统会把本次查询结果放到一块叫做 ARP 缓存的内存空间留着以后用。

也就是说,在发包时:

  • 先查询 ARP 缓存,如果其中已经保存了对方的 MAC 地址,就不需要发送 ARP 查询,直接使用 ARP 缓存中的地址。
  • 而当 ARP 缓存中不存在对方 MAC 地址时,则发送 ARP 广播查询。

ARP工作原理

以下以发送ICMP包为例,详细描述ARP解析过程:

  1. 首先PC1观察目的IP:192.168.2.1与本机IP:192.168.1.1是否在同一个网段
  2. 发现不在,因此看本机是否设置了网关,如果没有设置网关,PC1直接将ICMP包丢弃,显示目的不可达;发现设置了网关:192.168.1.254,于是执行步骤3
  3. 因为不知道网关的MAC地址,因此发送一个ARP包,获取网关MAC地址:源IP为PC1 IP:192.168.1.1,目的IP为PC1网关IP:192.168.1.254,源MAC为PC1 MAC:11-11-11-11-11-11,目的MAC为广播MAC:ff-ff-ff-ff-ff-ff
  4. 网关回应ARP包:源IP为PC1网关IP:192.168.1.254,目的IP为PC1 IP:192.168.1.1,源MAC为PC1网关MAC:33-33-33-33-33-33,目的MAC为PC1 MAC:11-11-11-11-11-11
  5. PC1得到网关MAC,接着发送ICMP包:源MAC为PC1 MAC:11-11-11-11-11-11,目的MAC为网关MAC:33-33-33-33-33-33,源IP为PC1 IP:192.168.1.1,目的IP为目标IP:192.168.2.1
  6. 路由器收到ICMP包,拆包,查IP-端口对照表,发现IP为192.168.2.0网段的数据,通过E2口发出,于是转发包给端口E2
  7. R1获取目标PC2的MAC,发送一个ARP包:源IP为E2 IP:192.168.2.254,目的IP为PC2 IP:192.168.2.1,源MAC为E2的MAC:44-44-44-44-44-44,目的MAC为广播MAC:ff-ff-ff-ff-ff- ff
  8. PC2发送ARP回应,R1得到目标MAC
  9. R1发送ICMP:源IP为PC1的IP:192.168.1.1,源MAC为E2的MAC:44-44-44-44-44-44,目的IP为PC2的IP:192.168.2.1,目的MAC为PC2的MAC:22-22-22-22-22-22
  10. PC2回应ICMP, 源IP为PC2的IP:192.168.2.1,源MAC为PC2的MAC:22-22-22-22-22-22,目的IP为PC1的IP:192.168.1.1,目的MAC为E2的MAC:44-44-44-44-44-44
  11. 路由器转发ICMP,源IP为PC2的IP:192.168.2.1,源MAC为E1的MAC:33-33-33-33-33-33,目的IP为PC1的IP:192.168.1.1,目的MAC为PC1的MAC:11-11-11-11-11-11
  12. PC1收到回应,完成一次PING 命令

出口 - 网卡

经过以上的步骤,数据就封装好了。但是网络包只是存放在内存中的一串二进制数字信息,没有办法直接发送给对方。因此,我们需要将数字信息转换为电信号,才能在网线上传输,也就是说,这才是真正的数据发送过程。

负责执行这一操作的是网卡,要控制网卡还需要靠网卡驱动程序

网卡驱动获取网络包之后,会将其复制到网卡内的缓存区中,接着会在其开头加上报头和起始帧分界符,在末尾加上用于检测错误的帧校验序列

  • 起始帧分界符是一个用来表示包起始位置的标记
  • 末尾的 FCS(帧校验序列)用来检查包传输过程是否有损坏

最后网卡会将包转为电信号,通过网线发送出去。

送别者 - 交换机

下面来看一下包是如何通过交换机的。交换机的设计是将网络包原样转发到目的地。交换机工作在 MAC 层,也称为二层网络设备

交换机的包接收操作:

  • 首先,电信号到达网线接口,交换机里的模块进行接收,接下来交换机里的模块将电信号转换为数字信号。
  • 然后通过包末尾的 FCS 校验错误,如果没问题则放到缓冲区。这部分操作基本和计算机的网卡相同,但交换机的工作方式和网卡不同。

这里其实就是数据包的解封装过程,只不过只会解封装到MAC层,即能看到数据包中的源和目的MAC地址就可以了。

计算机的网卡本身具有 MAC 地址,并通过核对收到的包的接收方 MAC 地址判断是不是发给自己的,如果不是发给自己的则丢弃;相对地,交换机的端口不核对接收方 MAC 地址,而是直接接收所有的包并存放到缓冲区中。因此,和网卡不同,交换机的端口不具有 MAC 地址

交换机二层转发原理:

交换机是有一张表,叫做cam表,用来记录MAC和交换机接口以及vlan信息的;

  • 当交换机收到一个数据包,会先看源MAC地址,看该源MAC 自己CAM表是否存在,

    • 如果不存在,就记录该数据包进入的接口和vlan,源MAC进入CAM表,
    • 如果存在,看接受的接口和原来绑定的接口是否一致:
      • 如果不一致,更改接口,刷新老化时间300S;
      • 如果一致,就直接刷新老化时间;
  • 接着查看目的MAC,看是不是自己的

    • 如果是自己的就自己解封装处理(三层交换机就做三层处理);
    • 如果不是自己的进行转发处理;转发处理则需要查看CAM表有没有目的MAC:
    • 如果有:看是否为接收数据包的接口:
      • 如果是:进行丢弃;
      • 如果不是:进行转发
    • 如果没有:对除了该接口以外的相同vlan(相同广播域)的接口进行泛洪;

当然了,如果接收方 MAC 地址是一个广播地址,那么交换机会将包发送到除源端口之外的所有端口。

以下两个属于广播地址:

  • MAC 地址中的 FF:FF:FF:FF:FF:FF
  • IP 地址中的 255.255.255.255

出境大门 - 路由器

路由器与交换机的区别:

  • 因为路由器是基于 IP 设计的,俗称三层网络设备,路由器的各个端口都具有 MAC 地址和 IP 地址;
  • 交换机是基于以太网设计的,俗称二层网络设备,交换机的端口不具有 MAC 地址。(当然了,现在都有三层交换机,同时有路由和交换功能)

路由器收到包后同样对数据进行解封装,但是路由器则将数据解封装到到网络层,即看到源和目的IP地址即可。

  • 首先查看解封装到MAC层时,需要确保数据包中的目的mac是自己的mac;
    • 如果不是,则丢弃处理,说明这不是发给自己的数据包
    • 如果是,那么就继续解封装,查看目的IP地址
      • 若目的IP地址为自己,就继续解封装;
      • 若不为自己,就检查自己的路由表(FIB)是否有去往这个IP地址网段的路由
        • 若路由表中不存在,则丢弃该报文;
        • 若存在,则将该报文发给该路由下一跳,重新封装数据,将源MAC设置为自己,目的MAC为下一跳MAC,这里会查看下一跳MAC是否在ARP表中存在,若不存在,作ARP处理,若存在,就直接进行封装转发。

由于网络中的路由器一般都会配上对应的路由规则,所以正常情况下,数据都能最终发送到服务器端。

互相扒皮 - 服务器与客户端

当数据到服务器端了,服务器就能将数据进行完整的解封装了,可以直接解封装到 应用层(如HTTP)数据信息。这个解封装过程与上面的 MAC层,网络层 的解封装规则一致。

大致过程如下:

  • 数据包抵达服务器后,服务器会先解封装数据包的 MAC 头部,查看是否和服务器自己的 MAC 地址符合,符合就将包收起来。
  • 接着继续解封装数据包的 IP 头,发现 IP 地址符合,根据 IP 头中协议项,知道自己上层是 TCP 协议。
  • 于是,解封装 TCP 的头,里面有序列号,需要看一看这个序列包是不是我想要的,如果是就放入缓存中然后返回一个 ACK,如果不是就丢弃。TCP头部里面还有端口号, HTTP 的服务器正在监听这个端口号。
  • 于是,服务器自然就知道是 HTTP 进程想要这个包,于是就将包发给 HTTP 进程。
  • 服务器的 HTTP 进程看到,原来这个请求是要访问一个页面,于是就把这个网页封装在 HTTP 响应报文里。

HTTP 响应报文也需要穿上 TCP、IP、MAC 头部,不过这次是源地址是服务器 IP 地址,目的地址是客户端 IP 地址,这就又是一次数据包的封装过程了。

最后,客户端要离开了,不需要再向服务器发起通信了,则会向服务器发起TCP 四次挥手,至此双方的连接就断开了。

参考链接

来源:https://www.xiaolincoding.com/ ,Seven进行了部分补充完善

seven97官方微信公众号
seven97官方微信公众号