基础 - 输入网址到网页显示发生了什么
数据封装解封装
在数据传输过程中要遵循对等层次通信,每一层都与另一方对等层次进行通信 网络层-网络层、数据链路层-数据链路层。 而这些对等通信,并非直接进行的。而是由下层逐层封装来完成对等层交换数据,这就是我们数据的封装。 而解封装,就是上层需要与下层进行通信,于是逐层解封装至目标层进行通信。 这里的上下层就是指的网络参考模型的层次。
上面可能说的有点复杂不易于理解,可以记住下面这句话:数据发送时,从上至下逐层封装;数据接收时,从下至上逐层解封装;只有拆除外层封装,才能看到内层封装。
数据封装过程:
- 数据从应用层发出,进入
传输层
- 在
传输层
会为数据打上TCP or UDP
头部,里面包含了数据的源端口、目的端口
,到这层的时候,数据已经被封装成了数据段
。 - 数据段从传输层发出,进入
网络层
,在网络层,会为数据段打上一个IP头部
里面包含了数据段的源IP 、目的IP
,这时候在网络层的数据段被封装成了数据包
。 - 数据包从网络层发出,进入
数据链路层
,在数据链路层会封装一个以太网帧头部
里面包含了二层数据源MAC、目的MAC地址
,这时候数据包已经被封装成了数据帧
, - 最后,数据帧从数据链路层发出,进入
物理层
,在这里将由物理层将帧转换为01011二进制形式的比特流
在网络进行传输。
注意,数据的封装、解封装都是逐层进行的,不会出现跃层通信
数据的解封装同封装原理一样,只不过顺序进行了颠倒,从物理层的二进制数据流开始逐层解封装
直至应用层
假设应用层程序是HTTP,过程如下:
应用层 - HTTP
应用层其实就是将数据封装成最后的HTTP报文,能够通过TCP的协议号看到上层是HTTP这个应用程序。
而浏览器首先做的第一步工作就是要对 URL
进行解析,从而生成发送给 Web
服务器的请求信息。
先看看一条长长的 URL 里的各个元素的代表什么,见下图:
所以 URL 实际上是请求服务器里的文件资源。
当没有路径名时,就代表访问根目录下事先设置的默认文件,也就是 /index.html
或者 /default.html
这些文件,这样就不会发生混乱了。
对 URL
进行解析之后,浏览器确定了 Web 服务器和文件名,接下来就是根据这些信息来生成 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 请求,问 www.server.com 的 IP 是啥,并发给本地 DNS 服务器(如windows电脑中 填写的 DNS 服务器地址)。
- 本地域名服务器收到客户端的请求后,如果缓存里的表格能找到 www.server.com,则它直接返回 IP 地址。如果没有,本地 DNS 会去问它的根域名服务器:“老大, 能告诉我 www.server.com 的 IP 地址吗?” 根域名服务器是最高层次的,它不直接用于域名解析,但能指明一条道路。
- 根 DNS 收到来自本地 DNS 的请求后,发现后置是 .com,说:“www.server.com 这个域名归 .com 区域管理”,我给你 .com 顶级域名服务器地址给你,你去问问它吧。”
- 本地 DNS 收到顶级域名服务器的地址后,发起请求问“老二, 你能告诉我 www.server.com 的 IP 地址吗?”
- 顶级域名服务器说:“我给你负责 www.server.com 区域的权威 DNS 服务器的地址,你去问它应该能问到”。
- 本地 DNS 于是转向问权威 DNS 服务器:“老三,www.server.com对应的IP是啥呀?” server.com 的权威 DNS 服务器,它是域名解析结果的原出处。为啥叫权威呢?就是我的域名我做主。
- 权威 DNS 服务器查询后将对应的 IP 地址 X.X.X.X 告诉本地 DNS。
- 本地 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 分割数据
如果 HTTP 请求消息比较长,超过了 MSS
的长度,这时 TCP 就需要把 HTTP 的数据拆解成一块块的数据发送,而不是一次性发送所有数据。
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 地址,用于两点之间的传输。
一般在 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解析过程:
- 首先PC1观察目的IP:192.168.2.1与本机IP:192.168.1.1是否在同一个网段
- 发现不在,因此看本机是否设置了网关,如果没有设置网关,PC1直接将ICMP包丢弃,显示目的不可达;发现设置了网关:192.168.1.254,于是执行步骤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
- 网关回应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
- 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
- 路由器收到ICMP包,拆包,查IP-端口对照表,发现IP为192.168.2.0网段的数据,通过E2口发出,于是转发包给端口E2
- 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
- PC2发送ARP回应,R1得到目标MAC
- 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
- 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
- 路由器转发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
- 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进行了部分补充完善