数据封装解封装
在数据传输过程中要遵循对等层次通信,每一层都与另一方对等层次进行通信 网络层-网络层、数据链路层-数据链路层。 而这些对等通信,并非直接进行的。而是由下层逐层封装来完成对等层交换数据,这就是我们数据的封装。 而解封装,就是上层需要与下层进行通信,于是逐层解封装至目标层进行通信。 这里的上下层就是指的网络参考模型的层次。
上面可能说的有点复杂不易于理解,可以记住下面这句话:数据发送时,从上至下逐层封装;数据接收时,从下至上逐层解封装;只有拆除外层封装,才能看到内层封装。
数据封装过程:
数据从应用层发出,进入
传输层在
传输层会为数据打上TCP or UDP头部,里面包含了数据的源端口、目的端口,到这层的时候,数据已经被封装成了数据段。数据段从传输层发出,进入
网络层,在网络层,会为数据段打上一个IP头部里面包含了数据段的源IP 、目的IP,这时候在网络层的数据段被封装成了数据包。数据包从网络层发出,进入
数据链路层,在数据链路层会封装一个以太网帧头部里面包含了二层数据源MAC、目的MAC地址,这时候数据包已经被封装成了数据帧,最后,数据帧从数据链路层发出,进入
物理层,在这里将由物理层将帧转换为01011二进制形式的比特流在网络进行传输。
注意,数据的封装、解封装都是逐层进行的,不会出现跃层通信
数据的解封装同封装原理一样,只不过顺序进行了颠倒,从物理层的二进制数据流开始逐层解封装直至应用层
假设应用层程序是HTTP,过程如下:
简单的网络模型
应用层 - HTTP
应用层其实就是将数据封装成最后的HTTP报文,能够通过TCP的协议号看到上层是HTTP这个应用程序。
而浏览器首先做的第一步工作就是要对 URL 进行解析,从而生成发送给 Web 服务器的请求信息。
先看看一条长长的 URL 里的各个元素的代表什么,见下图:
URL 解析
所以 URL 实际上是请求服务器里的文件资源。
当没有路径名时,就代表访问根目录下事先设置的默认文件,也就是 /index.html 或者 /default.html 这些文件,这样就不会发生混乱了。
对 URL 进行解析之后,浏览器确定了 Web 服务器和文件名,接下来就是根据这些信息来生成 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 请求,问 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 连接状态查看
TCP 分割数据
如果 HTTP 请求消息比较长,超过了 MSS 的长度,这时 TCP 就需要把 HTTP 的数据拆解成一块块的数据发送,而不是一次性发送所有数据。
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解析过程:
首先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:FFIP 地址中的
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 四次挥手,至此双方的连接就断开了。
简单版总结
浏览器解析 URL,根据请求信息生成对应的 HTTP 请求报文。
DNS 解析:请求需要知晓服务器域名对应的地址才能通信,浏览器会检查本地缓存、操作系统缓存,甚至路由器续存。如果未命中缓存,浏览器向配置的 DNS 服务器发送查询请求,DNS 服务器递归查询最终返回 Ip 地址
TCP或者UDP:接着浏览器会调用 Socket 库委托协议栈工作,根据指定的情况选择TCP 或 UDP。如果使用 TCP,需要通过三次握手建立连接。需要在数据发送前通过三次握手与服务端建立连接。此时得到了封装了 HTTP 数据的 TCP 数据包。
IP:在TCP 数据包的基础上,再封装源地址 IP 和目标地址 IP 等信息,得到网络包。有了IP 就能在多个网络节点中确定数据包的传输路径,最终能找到目标服务器
MAC:得到网络包后,需要在 IP 头部的前面加上 MAC 头部,封装发送方 MAC 地址和接收方目标 MAC 地址。MAC 用来确保子网内设备两点之间的通信寻址。(IP 是多个网络节点传输寻址)
网卡:这个时候,网络包还是存储在内存中的二进制数据,需要网卡把二进制数据转换为电信号,通过网线进行传输。
交换机:通过网线会连到交换机,交换机是二层网络设备。工作在 MAC层,它会根据数据包中的 MAC 头找到另一个设备连接在交换机的哪个端口,然后传输。如果找不到对应的端口,则会向交换机上的所有端口(除了源端口)广播
路由器:路由器也是进行转发,但它是三层网络设备,包含IP层。利用路由器,数据在不同网络节点之间转发,最后到达服务器
层层验证:服务器确认 MAC 地址匹配、IP地址匹配,如果是 TCP协议则看看序列号是否匹配,若匹配根据端口找到对应的监听进程,此时服务器上对应的应用就接收到数据了。
服务器处理:服务器接收到请求后,处理相应的业务逻辑,生成HTTP响应,这其间可能涉及到读取数据库、访问文件系统等,最终会生成响应给客户端(又是一层一层的封装TCP、IP、MAC等头部数据,得到最终传输的数据包),从网卡到交换机到路由器
浏览器接收响应并渲染页面:经过多个路由器转发后,浏览器最终会接收到服务器返回的响应,进行页面染展示
如果使 HTTPS 呢?那仅需提到三次握手后需要先进行 SSL/TLS 握手即可