信息时代的每个人都应该掌握的计算机网络知识,尤其是从事开发工作的程序员,更特别的是非计算机相关专业的程序员,这个文章帮你快速建立对网络的认知,有帮助记得给我点赞哦~关注不错过更新~
作为程序员,有天你去面试,考官上来就给你了一道开放性面试题,请问:「当我们在浏览器中输入https://www.baidu.com域名,然后回车,背后用到了哪些网络协议,数据包是怎么转发的,请简单做下解答」,对于这道题,厉害的人能讲半小时到一小时,而大部分人几分钟貌似就结束了😛
仔细分析下这道题,它考察的不是一个一个零碎的知识点,而是一个面,虽然没有统一标准答案,但通过面试者的回答,考官大概就能了解到当前面试者的水平。因为整体数据流,背后涵盖了大部分互联网架构模型。
好了,不卖关子了,我们看看这道题涉及到哪些网络知识吧。
输入域名后然后回车第一步要做的事情就是域名解析,啥是域名解析呢?在真实网络传输过程中,其实压根就不会用到域名这个东西。点对点传输是基于IP地址进行交互的,这里的IP地址相当于我们的身份证号,它是身份的唯一标识,而域名相当于我们的姓名。是不是记一个姓名比记身份证号简单多了。所以,网络传输的第一步就是做域名解析,通过域名将IP地址换回来,然后再进行后续操作。我们先简单看一下dns解析的原理:
简单来说,当我们在浏览器地址栏中输入某个Web服务器的域名时。用户主机首先用户主机会首先在自己的DNS高速缓存中查找该域名所应的IP地址。如果没有找到,则会向网络中的某台DNS服务器查询,DNS服务器中有域名和IP地映射关系的数据库。当DNS服务器收到DNS查询报文后,在其数据库中查询,之后将查询结果发送给用户主机。
现在,用户主机中的浏览器可以通过Web服务器的IP地址对其进行访问了。
关于DNS服务器的工作原理,这里也简单做下讲解,DNS解析过程如图所示:
整个查询过程还是比较长的,为了提高DNS的查询效率,并减轻根域名服务器的负荷和减少因特网上的DNS查询报文数量,在域名服务器中广泛地使用了高速缓存。高速缓存用来存放最近查询过的域名以及从何处获得域名映射信息的记录。
如果本地域名服务器不久前已经有用户查询过域名为y.abc.com的IP地址,则本地域名服务器的高速缓存中应该存有该域名对应的IP地址。因此,直接把高速缓存中存放的上次查询结果(即y.abc.com的IP地址)告诉用户。
这里再插播一个知识点,DNS请求为什么用UDP?能不能使用TCP。使用UDP 优势是不需要经过 TCP 三次握手的过程,从而大大提高了响应速度。但也有缺点,容易被地方运营商劫持, 给你推送垃圾广告。为了避免被劫持,很多大厂都用了HttpDNS,感兴趣的小伙伴可以深入了解一下。
第一步我们通过DNS换到了IP,接下来要讲的数据包转发。怎么理解数据包转发呢?这里简单举个例子,比如说你给远方的朋友写信,信写好后,先放到信封里。然后找到邮局,把信封投递出去。邮局收到你的信封后,根据信封上的地址,帮你送到朋友那里。朋友收到你的信封以后,拆开信封,看到了你写的祝福,然后进行回信,回信的过程跟你寄信过程一样。这样一来一回,就是一个完整的请求-响应。整个过程中:
信的内容就是原始的消息体
信封就好比是消息体的组装,组装的结果就是数据报文
邮局就是网关,他接收我们的信件,并统一进行分发
信封上写的地址就是DNS请求出来的IP地址
邮局送信过程就是IP数据包寻路过程,也就是所说的路由
有了上面的举例,我们对数据包的转发有了大概的认识,接下来我们详细讲一下数据包是如何转发的。在讲数据包转发之前我们先聊聊IP地址,因为数据包转发是基于IP地址的,IP地址分为私有地址
和公有地址
两种。 私有地址主要用于在局域网中进行分配,在 Internet上是无效的。这样可以很好地隔离局域网和 Internet,也能节省IP资源,而公有地址
是全球唯一的。私有地址
就好比你家的门牌号,公有地址
就好比小区名,快递员给你送快递的时候会先找到你家小区,然后才能根据你家门牌号把快递送给你对吧,如果你快递地址只写门牌号,快递人员就不知道该怎么送了,因为每个小区都可能有同样的门牌号。
私有地址分为3类
A类: 10.0.0.0~10.255.255.255 即10.0.0.0/8 共有16777216 个IP地址
B类: 172.16.0.0~172.31.255.255 即172.16.0.0/12 共有1048576 个IP地址
C类: 192.168.0.0~192.168.255.255 即192.168.0.0/16 共有65536 个IP地址
A类地址最多,C类最少。一般家里的路由器,会使用C类私有地址,一般公司的办公网或者线上应用会使用A、B类私有地址。 在Linux系统上可以通过ifconfig
或者ip a
查看IP地址。
这个图里面我们可以看到机器IP是10.10.64.55, 子网掩码是255.255.248.0,这里将IP以及子网掩码分别转换成二进制,如下所示
00001010.00001010.01000000.00110111
11111111.11111111.11111000.00000000
前21
位表示网络位,后11
位表示主机位,主机位地址个数是2的11次方。也就是2048个。这里的子网掩码该如何理解呢?简单来说就是为了隔离广播域,掩码越长广播域越小。如果掩码是24位,那主机个数是256个,这256个地址在同一个广播域。我们可以简单举个例子做个对比,假如说某个学校一年级总人数是100人,如果不分班,老师讲话,所有的学生都能听到,如果分了10个班,每个班只有10人,那老师讲话只有10个人可以听到。通过分班(子网掩码),可以很好隔离广播域。另外要注意的一点是,广播域越大,交换机设备的压力也会越大,因为同一个数据包需要复制多份发出去,所以有了子网掩码就能很好的规避这个问题。
当一台机器有了IP以及子网掩码以后,是不是就能直接发送数据报文了呢?No,No,No这里还有一个关键点没讲,那就是MAC地址,数据包在从网卡发送出去之前一定要知道下一跳的MAC地址,这里的下一跳包含2种场景:
1. 下一跳是网关
2. 下一跳是相同子网下的IP
如果你访问的是一个公网地址,那么数据包的下一跳会丢给网关,让网关接着转发。 如果说下一跳是同子网下的IP,那么它不需要经过网关,这时它会通过ARP广播查找同子网下的MAC,拿到目标IP+MAC后,数据包就可以正常转发了。
对于第一种场景我们看一下下图:
网关地址是10.10.64.1,网关的MAC地址也已拿到,这时如果我们访问223.5.5.5这个地址,因为目标IP和本机IP不在相同子网,数据包会直接发给网关。
对于第二种场景,假如我们访问的目标IP是10.10.64.56,由于目标IP同本机IP在相同子网,此时是不需要经过网关转发的。但数据包发送前要通过ARP广播拿到目标IP的MAC地址。
当前机器ARP表只有网关MAC,此时我们ping一下10.10.64.56看会发生什么。
我们可以看到在ping 10.10.64.56地址时,因为本机没有目标IP的MAC,首先它发送了一个ARP广播,问目标IP的MAC是多少,然后目标IP给了应答。本机拿到目标IP对应的MAC后,才会发送ICMP报文。此时查看arp表,可以发现目标IP所对应的MAC。我们再通过traceoute验证一下,可以看到路由只经过一跳便结束了,未经过网关。
另外,对于第一个场景,当网关拿到去往223.5.5.5地址的数据包该如何处理呢?它的处理方式跟刚才讲的方式一样,查找本地路由表,找到下一跳出口,然后将数据包转发出去。
上面我们介绍了数据包转发原理,接下来我们讲一下数据包封装所使用的网络协议,探究期间具体发生了什么?
右边是客户端,可以理解成我们浏览器,左边是服务器。中间涉及到TCP、IP、ARP网络协议。协议栈分为几个部分,分别承担不同的工作。上下关系是有一定的规则的,上面的部分会向下面的部分委托工作,下面的部分收到委托的工作并执行。
应用程序(浏览器)HTTP请求通过调用 Socket 库,来委托协议栈工作。协议栈的上半部分有两块,分别是负责收发数据的 TCP 和 UDP 协议,它们俩会接受应用层的委托执行收发数据的操作。
协议栈的下面一半是用 IP 协议控制网络包收发操作,在互联网上传数据时,数据会被切分成一块块的网络包,而将网络包发送给对方的操作就是由 IP 负责的。
此外 IP 中还包括 ICMP 协议和 ARP 协议。
IP 下面的网卡驱动程序负责控制网卡硬件,而最下面的网卡则负责完成实际的收发操作,也就是对网线中的信号执行发送和接收操作。
如果 HTTP 请求消息比较长,超过了 MSS 的长度,这时 TCP 就需要把 HTTP 的数据拆解成一块块的数据发送,而不是一次性发送所有数据。
数据会被以 MSS 的长度为单位进行拆分,拆分出来的每一块数据都会被放进单独的网络包中。也就是在每个被拆分的数据加上 TCP 头信息,然后交给 IP 模块来发送数据。
这里添加的TCP头部,IP头部,MAC头部可以理解成一层一层的快递包裹盒。这里HTTP 是基于 TCP 协议传输的,TCP也称为可靠传输协议,我们简单看看TCP报文格式:
首先,源端口号和目标端口号是必不可少的,如果没有这两个端口号,数据就不知道应该发给哪个应用。接下来是包的序号,这个是为了解决包乱序的问题。在 HTTP 传输数据之前,首先需要 TCP 建立连接,TCP 连接的建立,通常称为三次握手。这个就不展开细说了,再说下去感觉天黑都讲不完。
下面简单讲讲IP协议:TCP 模块在执行连接、收发、断开等各阶段操作时,都需要委托 IP 模块将数据封装成网络包发送给通信对象。我们先看看 IP 报文头部的格式:
注意:在 IP 协议里面最重要的是源地址 IP 和目标地址 IP :
好了,TCP/IP这两个最重要的协议我们讲完了,TCP / UDP协议当中最重要两个数据是源端口
和 目的端口
,TCP面向可靠连接,而UDP面向非可靠连接。IP 协议里面最重要的是源地址 IP 和目标地址 IP 。日常所说的五元组
数据就是:源IP、源端口、目的IP、目的端口、协议 所组成。讲完网络协议,接下来讲一下流量接入。
经过DNS解析后,比如说这里www.baidu.com 域名解析的公网IP是180.101.50.242,然后通过http协议将数据包,发送到了这个公网IP,处理用户请求,并将流量送到应用的过程就是流量接入,这里我们简单看一副图:
客户端请求流量送到VIP以后,首先要经过的是4层负载均衡,4层负载均衡它的特点是性能好,但缺点是它只处理TCP、UDP、ICMP4层相关的协议,如果要处理HTTP 7层协议,那就需要用到Nginx7层代理,最终将数据包转发到服务器上。
互相扒皮 — 服务器与客户端
数据包抵达了服务器,服务器肯定高兴呀,正所谓有朋自远方来,不亦乐乎?
服务器高兴的不得了,于是开始扒数据包的皮!就好像你收到快递,能不兴奋吗?
扒皮模型
数据包抵达服务器后,服务器会先扒开数据包的 MAC 头部,查看是否和服务器自己的 MAC 地址符合,符合就将包收起来。
接着继续扒开数据包的 IP 头,发现 IP 地址符合,根据 IP 头中协议项,知道自己上层是 TCP 协议。
于是,扒开 TCP 的头,里面有序列号,需要看一看这个序列包是不是我想要的,如果是就放入缓存中然后返回一个 ACK ,如果不是就丢弃。TCP 头部里面还有端口号,HTTP 的服务器正在监听这个端口号。
于是,服务器自然就知道是 HTTP 进程想要这个包,于是就将包发给 HTTP 进程。
服务器的 HTTP 进程看到,原来这个请求是要访问一个页面,于是就把这个网页封装在 HTTP 响应报文里。
HTTP 响应报文也需要穿上 TCP 、IP 、MAC 头部,不过这次源地址是服务器 IP 地址,目的地址是客户端 IP 地址。
穿好头部衣服后,从网卡出去,交由交换机转发到出城的路由器,路由器就把响应数据包发到了下一个路由器,就这样跳啊跳。
最后跳到了客户端的城门把手的路由器,路由器扒开 IP 头部发现是要找城内的人,于是把包发给了城内的交换机,再由交换机转发到客户端。
客户端收到了服务器的响应数据包后,同样也非常的高兴,客户能拆快递了!
于是,客户端开始扒皮,把收到的数据包的皮扒剩 HTTP 响应报文后,交给浏览器去渲染页面,一份特别的数据包快递,就这样显示出来了!
最后,客户端要离开了,向服务器发起了 TCP 四次挥手,至此双方的连接就断开了。
好了,我们站在数据包
的视角简单总结下:
一开始我虽然孤单、不知所措,但没有停滞不前。我依然满怀信心和勇气开始了征途。
我很庆幸遇到了各路神通广大的大佬,有可靠传输的 TCP 、有远程定位功能的 IP 、有指明下一站位置的 MAC 等。
这些大佬都给我前面加上了头部,使得我能在交换机和路由器的转发下,抵达了目的地!
这一路上的经历,让我认识到了网络世界中各路大侠协作的重要性,是他们维护了网络世界的秩序,感谢他们!