43

苦练基本功--网络篇1 | BryantChang的博客

 4 years ago
source link: https://bryantchang.github.io/2019/06/02/net-protocol1/?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

苦练基本功--网络篇1

2019-06-02 阅读量 763

《趣谈网络协议》学后总结一

从写完之前的CPU profile之后,自己就去苦练基本功了,准备系统的学习下网络和操作系统等最基础的知识,为后面能够更加清晰的了解系统profile套路打好基础。这几周,自己主要在学习刘超老师在极客时间的课程《趣谈网络协议》,感觉第一次能够从整个的协议栈的角度理解网络各层次之间的关联。之前在大学阶段感觉也学过这些协议,但是,可能讲解缺乏层次,使得网络这门课当时成了自己最不愿意上的几门专业课之一。通过这次的重温,感觉自己总算是稍微能说自己懂一点点网络协议了~。所以,为了巩固下自己学习的成果,决定把他们总结成几篇博客,这几篇博客主要从两个角度来串起来不同网络协议的关系,一个是从家用网络,另一个则是数据中心的网络,毕竟作为一个大数据平台研发,一定要对数据中心的网络有一个概念,否则一些网络通告如果看不懂可能会掉到坑里。本篇文章我将以那道经典的面试题:”当我在浏览器上输入某个域名时所发生的”对常见的网络协议进行串联,这里面,我的核心目标是怎么能把我们常见的网络协议串联起来,并不是每个协议的细节部分,对于每个协议的细节部分,建议大家仔细学习下刘超老师的《趣谈网络协议》课程主页

热身章–七层和四层

在正式开始我们的串联前,首先还是大致给出互联网的四层以及七层协议的介绍,实际上,这些名词描述的都是相同的事情,其目标都是对整个网络分为了不同的层级,在传统的TCP/IP四层协议中,将整个网络分为了网络接口层、网络层、运输层以及应用层。而七层协议则是基于基础的四层协议,将一些协议进行了更加细致的划分,分为了应用层,表示层,会话层,传输层,网络层,数据链路层以及物理层。下图展示了七层和四层之间对应关系

tcp_ip_overview.png

下面的表格展示了各个层级的典型协议

tcp_ip_table.png

搭建上网环境

刚刚我给出了整个网络分层,之所以首先将整体的网络分层以及不同的分层情况。是要强调一点,不管是属于哪一层的协议,它都是向下完整的,例如IP是网络层的协议,但是依然需要下层协议保持完整,例如依旧需要自己的MAC地址以及对端的MAC地址。之前在大学每一层分别讲解可能正是因为没有讲清楚每层之间的联系,导致最后对于网络的认知仍然是不成系统的,最后很容易忘记。我后面的文章也尽量本着系统,完整的视角介绍网络的知识。下面正式进入正题,这篇文章会围绕一个经典的面试题,即”当在浏览器上输入一个域名后会发生的事情”,相信大多数码农都碰到过,网上也有各种各样的版本,个人认为这个问题真的是一个非常好的问题,它主要“好”在两个方面,首先,这不是一个有明确对错,每个人都能够依据自己的理解,给出自己认为正确的答案。另外,这道题可以充分的考察面试者的逻辑思维能力,对一个问题阐述的系统性。最重要的是,它真的可以考察面试者对于基础知识的掌握程度。这里我想说,这篇文章也是尽自己的努力来回答这道题,其中一定会有这样或那样的不周全或遗漏,这里请大家多多包涵和谅解。

建立通信通道–物理层,链路层与网络层

MAC与IP地址

既然是在浏览器上浏览网站,那么我们首先需要能够连上网,所以我们要在家里有一套能上网的设备。首先,需要一个介质,信号能够通过这个介质进行传输,这就是我们常说的物理层,在这一层,所有的数据都是二进制,物理层协议所做的事情就是提供一个数据传输的通道,既要保证数据能够正确的通过通道,还要保证一定的传输带宽。说到带宽,从最开始时的电话线到现在的光纤,带宽有了质的飞跃。这一层更多的涉及到的是通信方面的专业知识,可能这方面的专业人士能够顺着这个话题深入写出很多。这里我们还是着重介绍上层的协议,物理层就不在展开。谈到两台设备之间通信,最简单的就是两台机器间通过网线进行连接,两台机器进行通信(这里先不说是否能访问外网)。既然是通信,那就一定要有某种地址来提供给设备,让其找到对端设备,并将网络数据发送给对端。计算机之间通信是通过网卡,每一张网卡上都会分配一个唯一的标识,我们称之为MAC地址(介质访问控制),介质访问控制其实是一种协议,算在数据链路层中,主要作用是为了解决以下三个问题

  • 数据包发给谁,谁来接收
  • 数据包发送的顺序

MAC地址一般就是我们通过在自己机器上输入ifconfig,ipconfig或者ip addr所看到的ether这一栏,如下图所示

mac_addr.png

我们通过这个地址能够唯一找到某一台设备。说完了地址,我们来看协议,协议就是两个设备间在某个层次上面的沟通规则,协议会分不同的层级,有二层的,或三层的亦或是更高级的应用层,MAC协议就是一种常见的二层协议,用于完成最基本的数据传输。其数据包结构如下

mac_stru.jpg

(该图片来自网络)

我们需要向对端发送数据,首先需要放进自己的MAC地址和对方的MAC地址。然后,我们发送数据可能是为了某种特定的目的,因此设定了专门的位置标识上面三层协议的类型,例如IP/ARP等。最后的几位是用于数据校验的,中间则为数据位,提到数据位,这里需要提个配置,MTU,这个配置代表了最大传输单元,定义了上层协议最大的传输大小,如果超出了这个大小,则需要进行分片进行传输。这里面默认值为1500,至于为何选择1500,可以参考这篇文章为什么MTU值普遍都是1500

有了MAC地址就有了设备间相互通信的基础,这就相当于每个人有了身份证。但是光有身份证还不够,如果我需要联系到一个人,但我只知道他的身份证号和名字,这可能会让我们很抓狂,根本无从找起。这时候可能我们需要他在提供一个关键信息,那就是家庭地址。有了了这个地址,我们可以直接极大的缩小查找范围,直接到家里面敲门,直接向里面的人问,xxx是住在这里面吗?这样本人极有可能就会出来应答。实际上想想这个过程,真的是与下面要提到的网络层干的事情非常非常相似。网络层也有一个地址,这就相当于我们的家庭住址,这个地址就是大家都最熟悉不过的IP地址。这个不需要多说,IP地址分为Ipv4与Ipv6地址,在我们查看自己的地址时,都会看到我们的设备上有一个v4地址和v6地址,如图所示,v4地址是32位,使用10进制标识,v6地址为128位,使用16进制标识。

ip_addr.png

v4的IP地址有三类,每一个类型中都有属于自己类型的私有地址,用于局域网间的网络组织,其他部分是公网地址,用于广域网中的通信。IP地址中有一个很核心的算法,这个方法的最核心作用就是判断这个地址是不是某个网段的,也就是说用这个方法能够判断出这个人是不是属于这个小区或这个门牌号。这就是CIDR(无类别域间选择)。

CIDR–网络界表示门牌地址的通用方式

CIDR下的IP地址使用如下方式标识

xxx.xxx.xxx.xxx/yy

其中yy代表的是子网使用的位数,ipv4是由32位2进制构成,例如上图中的ip为192.168.4.31/24 其中24代表网络所占的位数,而32-24=8代表了主机数量,所以这个网段能够覆盖2^8=256台主机。而这个网段的子网地址确认则为这个地址的任一ip地址按位与子网掩码,子网掩码则是网络位数全置为1,后面全为0,这样按位与就可以定位到这个ip的子网地址。除子网掩码外,还有两个比较重要的地址,一个是广播地址,向这个地址发送数据,所有子网内的机器都能收到消息。另外一个地址,则是网关地址,网关地址是后面外网通信的重要地址,后面介绍网关时会重点介绍。具体的子网规划,划分网段的方法可以查看相关资料。

有了这个IP地址,就相当于我们知道了这个人的地址,那么我们要找到这个人,首先就先到这个人所在的地址(例如某街道,某小区,甚至是这个人的家中),然后来吼,身份证号是xxx的人是谁。也就是说,有了IP地址,我们就真正能够实现通信了。

但是我们会发现一个问题,当我们开机时,计算机是没有IP地址的,只有和计算机网卡绑定的MAC地址。而且,比如我拿的是笔记本,那么在我家和在公司IP地址肯定不是一个,问题就来了,这个IP究竟是咋来的呢?

IP如何悄悄被设置到了我们的计算机

我们有两种方式设置IP地址,一种是通过手动设置IP地址,windows和linux系统都可以有对应的方式设置IP地址。为了不让IP变化,一般会指定IP地址,但是如此设置IP地址的方式需要用户对IP地址的工作机制有一些了解。因为如果设置不正确,就无法设置成局域网进而进行通信了。一般情况下,我们都会让相关的设备自动为我们分配IP地址。其中所用到的就是DHCP协议,这个设备一般都是路由器,DHCP的主要原理就是我们从某个网段中抽出一部分IP地址用于租用。每次有新设备接入时,都会通过向DHCP发送请求(一般叫做DHCP Discover),DHCP收到请求后,会从自己管理的公共IP地址选取一个返回给这个设备,同时记录MAC与IP的对应关系表示这个IP地址已经租出去。这里我用一张图简单看DHCP的路由器配置

dhcp_router.png

这里我们看到我们将192.168.1.100—192.168.1.199作为活动地址用于租赁,同时我们将租约的超时时间设置为120min,当然这也不代表到了过期时间就会重新分配IP地址,这样的话IP地址分配的性能会收到影响,同时IP地址也会经常变化。一般情况下是当租约快到期时,租方会主动向DHCP发送请求表示自己还将续租这个IP地址,这样在路由器中会继续维护这个IP和MAC地址的对应关系。

IP是如何与MAC是怎么联系起来的

现在我们有了MAC地址以及IP地址,那么有个问题就来了,我们知道了一台机器的IP地址,计算机到底是如何获取到它的MAC地址,从而与对方进行通信呢?这就牵扯到另一个网络层的协议,ARP,一句话来概括这个协议,就是“已知IP求MAC”,在MAC层的数据包中会有一个2byte的类型字段,其中可以表示IP或ARP等网络协议。ARP协议的大致流程是,机器知道对端的IP地址,但不知道MAC地址,所以这台设备会在整个网络中广播ARP请求,里面会有对端的IP地址,只有对应的设备会对这个请求进行应答,为了避免每次都是用ARP请求,机器本身会缓存ARP的结果,到了某个过期时间会重新发送ARP请求。

arp.png

(该图片来自网络)

二层设备到三层设备

对于两台机器来说,如果想要彼此通信,那么可以使用一根网线将两台机器连接起来,使用手动设置IP地址的方式将两者设置成同一个网段,那么理论上讲这两台机器就可以进行通信了。这两台机器构成了一个最简单的局域网(LAN),然而当机器变成3台就无法进行这样的通信了,因为需要两两联通,那么就需要一些特定的设备。早期的时候,我们会使用集线器(Hub),集线器的原理是所有从一台设备发出来的数据包都会广播到其余所有的设备上,然后其他设备按需获取所需要的数据包进行处理。但是这种设备会有个问题,就是如果设备较多时,链路上会出现比较大的拥塞,举一个比较实际的例子,一个LAN中部署一个对外的HDFS应用,这类数据存储引擎为了能够保证引擎的高可用性,会对每一份数据设置多个副本,多个副本之间会进行频繁的数据复制,如果设备之间的通信全部使用了Hub,大量的数据流量在不同设备之间广播,显然会使得数据复制异常低效从而影响整个集群的性能。

针对Hub在数据传输上效率较低的问题,我们就希望设备能够记住端口和MAC地址的映射关系,如此一来,当一台机器发出数据包时,这台设备会把MAC头拆出来解析,并查询MAC和端口的映射关系表,就能“有的放矢”的将数据包发送到指定的端口。这也就发展成了后面的交换机,因为这类设备会自己解析数据包的MAC头,MAC头在TCP/IP协议栈中属于第二层,因此也被称为二层设备。那么交换机是如何做到智能的呢?在开始的时候,这个映射关系是空的,因此设备发送的数据包仍然会以广播的形式发送出去,与Hub不同的是,MAC会记住发出去的设备MAC和端口号的关系,以此类推,当某台设备想要往这台设备发送数据时,交换机将这个数据包的MAC地址解析出来,通过查询端口和MAC地址的映射关系,将数据包转发到对应的端口上。

刚刚我们是将不同的设备放入到了一台交换机上,多个交换机连接在一起,就形成了一个拓扑结构。多台交换机之间形成的拓扑,如果拓扑之间形成了环路那么各自的交换机的功能就会退化,因为它们似乎都不确定到底这台设备是不是属于我的管辖范围之内。网络协议里使用基于“最小生成树”的STP协议来破环,总体来说是将交换机分为多个层级,分为根交换机,指定交换机等,具体的协议工作流程详见交换机与VLAN:办公室太复杂,我要回学校。对于多个局域网间的保护机制,在二层上主要是通过隔离来解决,隔离的方式有两种,物理隔离和虚拟隔离,物理隔离则是使用多个交换机组成多个局域网,然后多个局域网间进行物理隔离。然而这样对硬件资源有较大的浪费,例如某我只有四五台设备,但是需要隔离成三个不同的局域网,那么我就需要三台交换机来完成这个需求。显然是浪费资源,这就有了下面的VLAN协议,将不同的局域网按照一个唯一的ID(VLAN-Id),这个ID位于MAC的数据包中,其中就包含VLAN ID,位数为12位,这就意味着最多能够分割为4096个局域网。在这种情况下,交换机之间的链接可能会受影响,这里面交换机会通过Trunk口进行通信,这个口会转发任何VLAN ID发过来的数据包,交换机之间通过这个口进行连接和通信。

三层设备与二层设备类似,三层设备是能够将IP地址抽取出来进行解析,最核心的设备是路由器,三层设备与二层设备最核心的区别在于,交换机多用于局域网之间的连接,而路由器则多涉及外网之间的互连。如果ip需要访问同一个网段中的其他设备,则是通过交换机,因为同一个网段内就有MAC地址的用武之地。而如果访问不再一个网段的设备,则就需要路由器的功力了,因为路由器一般都充当着“网段守护者”的角色,学术名词称为网关。路由器的核心维护着一张“路由表”,路由表类似一张地图,通过路由表我们可以选取下一个需要到达的网关,这里称作跳,可以想像,如果需要跨越多个路由器,那么网络包会通过一个又一个的路由器,好似跳棋,一跳一跳最终到达目的地。举例说明,当一台设备试图访问不再一个网段的设备时,我们会先判断这个设备与目标设备是否为同一个网段,如果是同一个,则直接发送ARP请求,获取目标设备的MAC,然后直接向目标设备发送网络包。如果不是同一个网段,那么会将数据包发送到网关,通过ARP获取网关的MAC,向网关发送数据包,但目标IP还是对面设备的IP。随后网关所对应的路由器会查询路由表,通过route可以看到某台机器的路由表。可以看到其中某条记录如下

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.0.0.10       10.139.128.1    255.255.255.255 UGH   0      0        0 eth0

其中各个字段的含义如下

Destination:目标网络或主机,为0.0.0.0时,表示是默认网关,所有的数据都发到这个网关
Gateway:网关地址,0.0.0.0标识当前记录对银行股的Destination和本机在同一网段,通信是不需要再经过网关(最后一跳)
Genmask:Destination的子网掩码,Destination是主机时会设置成255.255.255.255,是默认路由时会设置为0.0.0.0
Flags:标记,其中U---路由是活动的,H---目标是主机,G---需要经过网关,R---恢复动态路由产生的表项,D--路由后台程序动态安装,M--由路由器后台程序修改,!--拒绝访问
Metric:路由举例,到达指定网络所需的中转数
Ref:路由项引用次数
Use:此路由项被路由软件查找的次数
Iface:网卡名字

例如上面的路由项,这是一个主机路由,即如果要到达10.0.0.10这台主机,需要通过10.139.128.1这台网关,再如下面这条记录

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.0.0.0       10.139.128.1    255.255.255.255  UG   0      0        0  eth0

这是一条网络路由,表示如果需要到达10.0.0.0/24这个网络,需要经过10.139.128.1这台网关。

对于路由表的设置有两种方式,分别为静态路由与动态路由协议,静态路由用于比较简单的网络拓扑建设,可以通过linux route命令添加。例如

route add -host 10.0.0.10 netmask 255.255.255.255 gw 10.139.128.1 dev eth0 ##设置网络路由
route add -net 10.0.0.0 netmask 255.255.255.0 gw 10.139.128.1 dev eth0 ##添加网络路由

而动态路由则是基于数据结构中的图中最短距离的算法实现,图中求最短距离的方法有两个,分别为

  • Bellman-Ford
  • Dijkstra

基于这两种算法诞生了两种路由算法,分别为

  • 距离矢量路由 — 外网路由协议(BGP),不同的网络之间形成了若干个AS(自治系统)
    • iBGP:自制系统内部的协议,负责将边界路由的学习情况导入到自治系统内部
    • eBGP:边界之间的路由协议
  • 链路状态路由算法 — OSPF,一种内部网关协议(IGP)–通过等价路由进行负载均衡

上网前最后一项准备,ping一下

通过设置交换机,路由器,我们已经可以上网了,如何确认我们能够连接上对端设备呢?相信所有人的答案基本一致,ping一下,不仅是计算机专业的同学,甚至其他同学也会这个方法。下面简单介绍一些ping的工作原理,让大家更清楚的了解这其中的原理,这里面可能会将我们上面讲到的协议全部用到,相当于上面介绍协议的总结。

ping基于的是ICMP协议,ICMP属于网络层协议,与IP协议属于同一层,其数据包格式如下图所示

icmp_stru.png

(该图片来自网络)

ICMP包含两种类型,分别为查询报文类型以及差错报文类型,其中查询报文是客户端主动发起的,我们用到的ping用到的就是查询报文类型。ping的主动请求成为ICMP ECHO REQUEST,请求的回复成为ICMO ECHO REPLY。相比原生ICMP,ping中多了两个字段,其中一个为标识符,另一个为序号。下面简单介绍ping命令的流程

ping_icmp.jpg

(本图片来自网络)

图中展示了一个典型的ping命令示例,假设A的IP地址为192.168.1.1,主机B的IP地址192.168.1.2,ping命令执行时,源主机首先构建了一个ICMP的请求包,其中核心包含类型字段和序列号。每发出一个数据包,序列号+1。随后有ICMP协议将数据包和IP地址192.168.1.1一起交给IP层。将源地址设置为本机地址,目标地址设置为192.168.1.2构建一个IP包。
随后需要装填MAC地址,由于两个地址在同一个自网内,所以直接通过ARP映射关系表获取目标主机的MAC地址,如果没有则构建ARP请求获取目标MAC。如果不再同一网段,则首先将数据发送到网关,网关是路由器,通过网关的路由表获取如何到达目标主机的网关,通过一跳一跳的路由,知道获取到目标的MAC地址。
主机B收到数据帧后,对比MAC地址,如果符合,则将包收入,然后判断IP地址,如果满足则将IP地址提取出来交给本机的IP层。主机B会构建一个ICMP应答包,数据类型为0,序号和请求数据序号相同。通过相似的方式发送给主机A。如果一段时间没有收到,则认为主机不可达,如果收到,则说明可达,用当前时刻减去该数据包从主机发出的时刻,即为包发送的延迟。
至此。我们终于完成了一套上网设备的搭建,这里面涉及的协议主要包含物理层,链路层,还有网络层。后面的文章中我将继续围绕输入url后发生的事情这个场景介绍数据究竟如何在网络之间进行传输,以及这些数据是如何被应用层应用。还包括url如何变换为ip,以及图片,网页等信息具体的访问方式等继续串讲网络协议。敬请关注~~~~


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK