我们如果要理解数据是如果在网络世界中穿梭的,那其实只要了解其中的三张表就可以了。这三张表分别为路由表、转发表、ARP 表。
假设我们用聊天工具聊天的时候,我在北京,你在广东,当我给你发送一条消息的时候。搭载这这条消息的数据包需要从我的设备(电脑或手机)出发,跨域千上万水,趟过万里光纤,在不出意外的情况下才能到达你的设备。在这个过程中数据包要经过大致流程如下:
1、数据在我的设备上从应用层向下层层封装,最后发送到路由设备上;
2、路由设备对数据包进行转发,可能经过不止一个路由器和交换机;
3、终于到达你的设备所在的子网路由器,你所在的子网路由器转发给局域网内所有的直接相连的主机或交换机,如果是转发给交换机的话,交换机再次转发给交换机上连接的设备;
4、当你的设备发现这个数据包的目的主机是自己,就开始对数据包进行自链路层向上的一层一层的解封装,最终由对应的应用程序拿到消息;
主要的流程就是这样,但是中间每一种设备的转发都有对应的规则,主要涉及的设备就是终端、交换机、路由器,接下来我们具体来梳理一下一个数据包这一路上是怎么跋山涉水才呈现到你的屏幕上的。
跋山涉水来找你
看下图,假设现在「子网A的主机A」要发一条消息给「子网B的主机x-1」,这两个主机分别在不同的子网,也就是说并不是局域网内的传输,中间经过了路由器A、路由器B、子网B的顶层交换机、交换机X,最终才到达了目标主机X-1。
主机A封装数据包并发送
如果你已经掌握了传输层、网络层、链路层的各个协议,那这个过程就相对来说非常简单了。
应用层某聊天工具发送消息,消息内容被处理之后,也就是上图中的用户数据。
经过传输层,使用 TCP 协议传输,TCP 将用户数据封装上 TCP 首部信息,形成一个 TCP 段。注意了,TCP 首部中含有源端口号和目标端口号,应用层会根据端口号决定哪个应用程序使用这个包。比如我们自己开发的聊天程序,端口用的是 18888,那这个包到达主机X-1之后,发现 TCP 协议头中的端口号是 18888,那就知道要把这个包交给我们开发的聊天工具处理了。
经过网络层,搭载IP协议,在TCP段的基础上,加上IP首部信息,形成IP数据报。注意了,IP首部含有源IP地址和目的IP地址,要不然网海茫茫,谁来接收它,它又回复谁呢。在这个 IP 数据报中,源IP就是主机A的IP,目的 IP 地址就是主机X-1的IP。
最后经过链路层,在IP数据报的基础上,加上以太网帧首部,形成以太网帧数据包。在以太网上,只有以太网帧能顺利通行。注意了,以太网帧首部包含源MAC地址和目的MAC地址,链路层只认MAC地址,有了它才能找到对应的终端。
经过层层包装后,真正跑到以太网上的数据最终必须是一个完整的以太网帧,而以太网帧中必须要有目的端的 MAC 地址。接下来就是怎么拿到目的端的 MAC地址了。
当发送端开始组装数据的时候,首先会检查目的IP 和自身的IP 是否处在同一个网络中。计算方式很简单,就是用 IP 地址和子网掩码进行「与运算」。
如果目的端在局域网内
如果得到的网络地址是一致的,说明在同一个网络中。
这时,ARP表就要上场了。
ARP 表记录着 IP 地址和 MAC 地址的映射关系。可以根据 IP 地址查到对应的 MAC 地址,然后放到以太网帧中,如果有的话。
发送端检查自己的 ARP 表中是否有目的 IP 对应的 MAC 地址。如果有的话,直接将 MAC 地址组装到以太网数据帧中,发送数据帧,数据就能被目的端顺利接收。如果ARP 表中不存在目的IP对应的 MAC 地址,则向本网络广播发送 ARP 请求,ARP 请求会带着目的IP地址,意思就是询问“谁的IP地址是这个,请回复你的MAC地址给我”,网络中的主机看到后,如果IP是自己的,就返回给发送端一个ARP回复,回复中带着自己的MAC地址,发送端拿到MAC地址后,先存入本地的ARP表,然后组装以太网帧,将数据发送。
如果目的端不在局域网内
如果得到的网络地址不一致,说明目的端不在本网络中。那这样的话,查询 ARP表是不可能查到对应的 MAC 地址的,因为 ARP 表只存储局域网内的 IP 和 MAC 地址的映射记录。
既然查不到那怎么办,总得发出去才行啊。
如果 ARP 表中查不到记录,那只能走默认网关了。我们的设备都是知道默认网关的 IP地址的,这时候再去 ARP 表查询是否有网关地址对应的 MAC 地址,如果有直接将网关的 MAC 地址封装到以太网帧的目的地址中。如果没有的话,仍然要像上面那样,广播发送 ARP 请求,获取网关设备的 MAC 地址,然后存入 ARP 表中。对应到上图就是路由器A的端口1的网卡地址。
那将网关的 MAC 地址当做目的 MAC 地址,还怎么找到最终的目的端啊,最终的消息也不是想发给网关啊。
没办法,就是这样的,这只是第一步,在后面经过每一个非最终目的端设备的时候,都要将目的 MAC 地址设置为下一跳设备的 MAC 地址,因为以太网帧就是这样设计的。所以说,在整个传输过程中,以太网帧会不断的解析然后重新封装,目的就是把下一跳的 MAC地址封装进去。直到最终到达了目的设备所在的网络。
目的MAC 地址是一跳一跳变化的,但是 IP 头中的目的 IP 地址是绝对不能变的,要不然就真的找不到了。
路由器A如何路由的
当数据包到达路由器A之后,就要走出子网A,奔向更广阔的网络世界了。还是结合上面的图来看,这个拓扑结构还是很简单的,真实情况下,可能要经过十几二十个路由设备。
数据包来到路由器之后,路由器要怎么处理呢,路由器会进行路由操作,也就是将这个包安排一条最合适的路径发出去。
这就要提到路由表了。
路由器中维护着一张路由表,主要存放网络、主机与下一跳的对应关系。例如下表这样:
目标 | 子网掩码 | 下一跳 | 网络接口 |
---|---|---|---|
192.168.8.0 | 255.255.255.0 | 0.0.0.0 | en0 |
114.21.1.0 | 255.255.255.0 | 114.21.1.100 | en0 |
0.0.0.0 | 0.0.0.0 | 192.168.8.1 | en1 |
大致的意思就是如果收到一个数据报,在当前路由器的路由表中寻找,一般目标都是一个网络地址(标明一个子网),把具体数据包的IP地址和当前路由表的子网掩码进行与操作,如果得到的结果和路由表目标栏一直,就转发给这条记录中的下一跳地址,从网络接口栏所记录的接口发出(也就是路由器上的网口或者叫端口)。
如果下一跳地址是0.0.0.0 ,表示这个目的IP地址就在当前网络中。那就不用路由器转发了,拿到目的IP的MAC地址,就可以直接发送了(获取MAC地址的方法,前面说过了,先查ARP表,没有的话,再用ARP广播请求获取)。
如果下一跳不是0.0.0.0,表示目的IP不是本网络的地址,就发给下一跳的地址。
如果在路由表中都没有找到匹配的目标网络,那就看有没有配置默认条目了,默认条目也就是目标是0.0.0.0的条目,表示任意的IP都可以通过此条目的下一跳(也就是默认网关)地址转发出去。
如果在路由表中没有找到任何匹配的目标网络,并且没有设置默认条目,那就直接将数据包丢弃,并返回一个 主机不可达的 ICMP 请求。
路由表分为静态路由和动态路由,静态就是需要人手工配置,路由表是固定不变的,动态路由是根据一些规则动态更新路由表数据,总之, 路由表最终会有一些描述网络拓扑结构的记录存在。
当路由器A收到数据包之后,解封装这个数据包,从下层网上拆,链路层拆出 MAC 地址,发现就是自己的,继续拆,拆到 IP 层,找到目的 IP 地址,拆到 IP 层就可以了。然后拿着这个目表 IP 地址在路右边中检索,看看是否正好有对应的目标网络。
拿192.168.8.0(子网掩码是255.255.255.0)这个目标网络来说,目标是一个网络地址,可以理解为一个子网(局域网),那如果IP数据报里的目标IP是192.168.8.8/24或192.168.8.188/24都能对应上这一条记录,因为这两个地址和子网掩码与操作之后,得出的网络地址都是192.168.8.0。于是就发给下一跳 0.0.0.0。
假设我们的目标IP是114.21.1.1,通过查表发现了正好有目标地址是114.21.1.0的记录,于是转发给下一跳地址 114.21.1.100,通过en0这个接口发出去,直接发送到了与之相连的子网B的顶层交换机。
如果没有找到对应的记录,查看是否有默认路由,也就是目的地址是0.0.0.0的记录,如果有的话,就发给默认路由对应的下一跳地址。如果连默认路由也没有,直接将包丢弃,然后回复给源IP 一个类型为主机不可达的ICMP包。告诉源主机,此路不通了,然后应用程序根据这个信息,选择新的应对策略。
子网B的交换机X转发包
数据包从路由器A出来之后先到了子网B的顶层交换机,然后经过顶层交互机的转发,转发给了子网B的交换机X。顶层交换机如何转发就不说了,和交换机X的转发过程是一致的。
交换机的转发就要说到转发表了。
在交换机中维护着一张叫做转发表的映射表。一台交换机上有很多个接口,每个接口连接一台设备。转发表记录的就是接口和所连接的设备的MAC地址的映射关系。交换机就是根据这张表将数据帧传输到指定的主机端口上的。
数据包走到交换机这里了,说明它离目的地已经不远了,已经找到目标主机所在的局域网内了。
当数据包到达交互机后,交换机检查自己的MAC表是否有数据帧中目的MAC地址的匹配条目,如果有,则会根据MAC表中记录的对应端口将数据帧转发出去,这一转发方式称为「单播」。
而如果没有,则会将该数据帧从非来源端口的其它全部端口发送出去,这一转发方式程序称为「广播」。。
假设交换机 X 收到数据包后,根据目标MAC地址查询转发表,没查到,这时候,交换机X就将包从端口1和端口2广播出去给主机X-1和主机X-2,主机X-1收到这个包后,对比目的MAC地址和自己的是否一致,结果发现这个包是发给自己的,会回复交换机X一个数据包,包含自己的(主机X-1)的MAC地址,这时,交换机X就将这个MAC地址和交换机上对应的端口的映射关系记录到转发表。这一过程通常称为「自学习」。
主机X-2发现包不是发给自己的,直接就忽略了。
到此为止,主机X-1就顺利收到包了,确切的说是一个以太网帧。
子网B的主机X-1收到包之后
主机X-1收到这个数据帧之后,链路层解析,发现正好是发给自己的,因为目标MAC地址和自己的一致,然后交给网络层,发现目的IP也是自己的,于是交给传输层,传输层解析TCP段,最后将数据交给上层的应用层,应用层根据TCP的目的端口号,判断是那个应用程序要处理收到的数据。
总结
下面的流程图是对上述过程的汇总,可以点开下面的大图查看。
其中有几个细节要理解,对理解整个过程有很大帮助。
1、链路层的以太网数据帧必须要有目的端的 MAC 地址,而且必须是下一跳的 MAC 地址。别问为什么,协议就是这么规定的。
2、正因为链路层以太网帧必须是下一跳MAC地址,所以整个传输过程中,以太网帧是一直解包、重组的,目的就是把下一跳MAC地址重组进去。
3、网络层 IP 协议中的目的 IP地址是不能变的,那有人要问了,发送端和目的端虽然不是在一个子网中,但它们的局域网地址都是 192.168.1 网段的,那怎么能找到目的主机呢。本篇并没有讨论这个问题,这其实就要牵扯到公网和内网的映射了,一个局域网最终会映射到一个公网 IP 地址上,比如路由器可以设置 NAT 功能。
4、ARP 协议只工作在局域网中,ARP 通过 IP 获取 MAC 地址,是通过向局域网内所有主机广播 ARP 请求的,只有对应的 IP 地址才会回复这个 ARP 请求。
5、每经过一个路由设备,都要将 IP 数据报拆包,然后再重组,源IP地址设置为自己的,然后 TTL 减一,TTL 有一个限制,比如 32,当路由次数超过这个数值,表示网络环境不是很好,绕的太远了,就会把这个包丢弃掉。