在浏览器输入一个网址期间发生了什么?

解析URL

首先浏览器做的第一步就是要对URL进行解析,从而生成发送给Web服务器的请求信息,让我们看一下URL包括什么,如图:

对URL进行解析之后,浏览器确定了Web服务器和文件名,接下来就是根据这些信息来生成HTTP请求消息了,

在浩瀚复杂的网络中,到底是如何通过这URL来发送到远在天边的服务器呢?

地址查询—-DNS

域名服务器

浏览器解析URL生成HTTP消息后,会通过操作系统发送给Web服务器。但是在发送之前需要进行服务器域名所对应的IP查询,因为操作系统的协议栈中的网络层是必须知道目的端的ip地址的。
就好比我们打电话的时候,必须知道对方的电话号码,但是电话号码难以记忆,所以我们会将对方电话号+姓名保存在通讯录里。
所以,有一种服务器专门保存了Web服务器域名和IP的对应关系,他就是DNS服务器。
DNS中的域名都是句点来分隔开的,比如www.server.com.越靠右的位置表示其层级越高,实际上域名后面还会有一个点,比如www.server.com.,这里最后一个.代表根域名在最顶层,它的下一层就是.com顶级域,再下面是server.com权威DNS服务器.

根域DNS服务器的信息保存在互联网中所有DNS服务器中,这样任何DNS服务器都可以找到并访问根DNS服务器了。因此客户端只要能够找到任意一台DNS服务器,就可以通过它找到根域服务器,然后一路顺藤摸瓜找到目标DNS服务器。

域名解析的工作流程:

1.客户端会先发出一个DNS请求,问www.server.com的IP是啥,发送给本地DNS服务器(也就是在客户端的TCP/IP设置中填写的DNS服务器地址,在Windows下是“控制面板”->”网络和Internrt”->”网络和共享中心”->”更改适配器设置”->右键当前网络连接(如Wwi-Fi/以太网)->”属性”->双击“Internet协议版本4 (TCP/IPv4)” 即可看到,在Linux下可以查看/etc/resolv.conf)
2.本地域名服务器收到客户端的请求后,如果缓存里找到则直接返回ip地址,如果没有本地DNS回去问他的根域名服务器,根域名服务器是最高层次的,他不会直接用于域名解析,但是会指出一条明路。
3.根DNS收到来自本地DNS请求后,发现后置是.com说”www.server.com”这个域名归.com区域管理,我给你.com顶级域名服务器地址给你,你去问问它吧”
4.本地DNS收到顶级域名服务器的地址后,去查询。
5.顶级域名服务器说,”我给你负责www.server.com区域的DNS服务器的地址,你去问他”.
6.本地DNS于是转向权威DNS服务器:”www.server.com对应的IP是啥呀?”,权威DNS服务器工作就是域名解析,查询后返回本地DNSIP地址是”x.x.x.x”
7.本地DNS再将IP地址返回给客户端,客户端和目标建立连接。

这就是DNS解析的全部过程,但是并不是每次解析域名都需要这么多的步骤,这样效率太低,因此需要使用到缓存,浏览器会先查看自身有没有对应域名的缓存,如果有直接返回,没有就去问操作系统,操作系统也会看自己的缓存,如果有就直接返回,如果没有再去hosts文件看,也没有才回去问本地配置的DNS服务器。

顺便提一下,这里的hosts文件是什么呢?
在 DNS 解析过程中,​hosts是操作系统中一个静态的本地域名解析文件,用于手动指定域名和 IP 地址的映射关系。它的优先级高于 DNS 查询,系统在进行 DNS 解析时,会首先检查hosts文件,如果文件中存在对应域名的记录,则直接使用该记录,而不会向 DNS 服务器发起请求。
比如我们可以手动配置域名和IP映射,覆盖全局DNS解析结果,127.0.0.1 localhost,或者将一些恶意的域名指向hosts文件中定义的无效ip 0.0.0.0,我们可以使用sudo nano /etc/hosts 来查看hosts文件中的配置。

实践

理论始终是理论,让我们实践来看一下DNS的过程,以Linux操作系统为例,首先要确定我们使用的DNS服务是什么?如(systemd-resolved、nscd或dnsmasq),我的是systemd-resolved,通过resolvectl statistics命令可以查看当前的缓存状态,如:

抓一下本地DNS服务的包:
1.sudo resolvectl flush-caches清空缓存
2.修改配置文件/etc/systemd/resolved.conf进行添加
[Resolve]
Cache=yes
#代表启用缓存
DNSStubListener=udp
#控制systemd-resolved 是否监听本地回环接口(127.0.0.53:53)的 DNS 请求,yes表示同时监听,no禁止本地监听,udp代表仅仅监听udp端口
3.sudo systemctl restart systemd-resolved
#重启DNS解析服务
4.sudo tcpdump -i lo -n port 53
#在本地回环接口(lo)上抓取所有53端口的DNS数据包
显示如下:

本地41241号端口向53号端口DNS服务询问www.fffxy.xin的ip,其中A代表ipv4,AAAA代表ipv6,查询完毕后53号端口程序返回给41241端口www.fffxy.xin的ip地址。

协议栈

通过DNS获取到IP之后,就可以把HTTP的传输工作交给操作系统的协议栈
协议栈的内部分为几个部分,分别承担不同的工作,上下关系是有一定的规则的,上面的部分会委托下面部分工作。


应用程序(浏览器)通过调用Socket库,来委托协议栈工作。协议栈的上半部分有两块,分别时负责收发数据的TCP和UDP协议,这两个传输协议会接受应用层的委托执行数据收发。协议栈的下面一半是IP协议控制网络包的收发操作,其中IP还包括ICMP协议和ARP协议。

  • ICMP:用于告知网络包传送过程中产生的错误以及各种控制信息。
  • ARP:用于根据IP地址来获取MAC地址。

传输层—TCP

HTTP协议是基于TCP协议传输的,让我们先了解一下TCP协议。
TCP报文头部格式:

源端口和目的端口:用于确定发送给哪个应用。
包序号:为了解决乱序问题。
确认号:确认发出去的对方是否接收到,为了解决丢包问题。
状态位:SYN是发起一个连接,ACK是回复,RST是重新连接,FIN是结束连接,TCP是面向连接的,因此双方要维护连接的状态,这些带状态位的数据包会引起双方状态变更。
窗口大小:TCP要做流量控制,双方各自声明一个窗口大小,标识自己的处理能力,别发送太快,撑死我,也别发送太慢,饿死我。除了流量控制还会做拥塞控制。
在HTTP传输数据之前,首先需要TCP建立连接,TCP连接的建立,通常称为三次握手。

可以使用Linux中的netstat -tanp查看TCP的连接状态。

如果HTTP的请求消息比较长,超出了MSS长度,此时TCP需要把HTTP的数据拆解成一块块的数据发送,而不是一次性发送完全部数据。

  • MTU:一个网络包的最大长度,以太网中一般为1500字节。
  • MSS:去除IP和TCP头部之后,一个网络包可以容纳的TCP数据的最大长度。

远程定位—IP

看一下IP报文头部格式:

源地址IP:就是客户端的IP地址。
目的地址IP:就是DNS域名解析出来的Web服务器的IP。
这里有一个问题:假设客户端有很多网卡,就会有多个IP地址,那IP头部的源地址应该选择哪个IP呢?
这个时候就要根据路由表规则来判断哪一个网卡作为源地址IP。
在Linux操作系统,可以使用route -n 命令查看当前系统的路由表。

通过目的IP和子网掩码进行与运算来抉择出从哪个网口发出报文。

两点传输—MAC

生成了IP头部之后,接下来网络包还需要在IP头部前面加上MAC头部。

如果是在局域网内传输数据,那么会通过广播ARP来获取目标主机的MAC地址。
如果在广域网中,则是通过不断更换目的端的MAC地址来实现数据包的传递。
至此网络包的报文如下:

出口—网卡

数据包只不过是在内存中的二进制数据,没办法直接发送给对方,因此,我们需要将数字信息转换为电信号,才可以在网线上传输,这才是真正的发送数据。
负责这一操作的是网卡,要控制网卡还需要网卡驱动程序,网卡驱动会在获取网络包之后将其复制到网卡内的缓存区中,接着在其开头加上报头和起始帧分界符,在末尾加上用于检测错误的帧校验序列。最后网卡将包转为电信号发送出去。

送别者—交换机

交换机是工作在MAC层的,也就是二层网络设备,是集线器的一种”升级版”。交换机的作用就是把数据包原样转发到目的地

交换机接收包流程

  • 电信号到达网线接口,交换机接收之后,将电信号转换为数字信号。
  • 通过包末尾的FCS校验错误,如果没有问题将网络包放到缓冲区。
  • 查询MAC地址表,查找接收方MAC地址是否在MAC地址表中有记录,如果有按照MAC地址表中指定的端口进行转发电信号即可,如果没有交换机会把数据包转发到除源端口外的所有端口上,无论该设备连接在哪个端口都可以收到数据包。这里思考一下,发送这么多冗余的包是否会造成网络拥塞呢?
  • 如果接收方MAC地址是一个广播地址,那么交换机会将包发送到除源端口之外的所有端口,广播地址(MAC:FF:FF:FF:FF:FF:FF,IP:255.255.255.255)。如果目的ip不在局域网内那么目的MAC填写就是默认网关也就是路由器。

上面的思考题,其实完全不必担心,因为以太网的设计本来就是将数据包发送到整个网络的,接收到网络包的计算机通过核对MAC地址选择丢弃,只有相应的接收者才会接收这个包。并且当目标设备接收了包之后会响应,因此交换机就可以将它的地址写入MAC地址表,下次也就不需要将数据包转发到所有端口了。

出境大门—路由器

  • 路由器是基于IP设计的,俗称三层网络设备,路由器的各个端口都有MAC地址和IP地址。它和计算机的网卡是一样的。
  • 交换机是基于以太网设计的,俗称二层交换机,交换机的端口不具有MAC地址。

接收包时,电信号到达网线接口部分,路由器中的模块会将电信号转为数字信号,然后通过包末尾的FCS进行错误校验,如果没问题则检查MAC头部中的接收方MAC地址,查看是不是发送给自己的包,如果是就放到接收缓冲区,不是就丢弃这个包。

当转发包时,路由器端口会接收发给自己的以太网包,然后路由表插查询转发目标,由相应的端口作为发送方将以太网包发送出去。

查询路由表确定输出端口
完成包接收操作之后,路由器会去掉包开头的MAC头部,MAC头部的作用是将包转发到路由器现在作用已经达到了,接着路由器会根据目的IP查询路由表判断要转发的下一个局域网路由器。

  • 注意,操作和上面的多网卡计算机确定源ip地址是一样的,那目的ip地址和子网掩码进行按位与操作,如果和条目中的目的ip匹配则查看网关地址就是下一跳的ip地址,然后通过ARP协议通过ip地址获取MAC地址。
    看这个路由表是不是有些奇怪,前两行的网关地址为空,这是因为如果结果落在前两行那么表示已经无需进行转发,此数据包的目标主机就在当前局域网内。
  • 如果网关地址不为空,则需要进行转发,但是我们需要的是MAC地址,此时只有网关的ip地址,并且这两个是独立的局域网如何获取MAC地址呢?虽然ARP是局域网协议,但是只要运营商通过技术手段将两个站点合并到同一个逻辑子网中,此时为以太网型广域网,此时ARP依然可以在”虚拟局域网”内生效。

服务器与客户端

数据包抵达服务器后,服务器会先扒开数据包的MAC头部,查看是否和服务器自己的MAC地址符合,
符合就将包收起来。
接着继续扒开数据包的IP头,发现IP地址符合,根据IP头中协议项,知道自己上层是TCP协议。
于是,扒开TCP的头,里面有序列号,需要看一看这个序列包是不是我想要的,如果是就放入缓存中然后
返回一个ACK,如果不是就丢弃。TCP头部里面还有端口号,HTTP的服务器正在监听这个端口号。
于是,服务器自然就知道是HTTP进程想要这个包,于是就将包发给HTTP进程。
服务器的HTTP进程看到,原来这个请求是要访问一个页面,于是就把这个网页封装在HTTP响应报文
里。
HTTP 响应报文也需要穿上TCP、IP、MAC头部,不过这次是源地址是服务器IP地址,目的地址是客户端
IP地址。
穿好头部衣服后,从网卡出去,交由交换机转发到出城的路由器,路由器就把响应数据包发到了下一个路
由器,就这样跳啊跳。
最后跳到了客户端的城门把守的路由器,路由器扒开IP头部发现是要找城内的人,于是又把包发给了城
内的交换机,再由交换机转发到客户端。
客户端收到了服务器的响应数据包后,同样也非常的高兴,客户能拆快递了!
于是,客户端开始扒皮,把收到的数据包的皮扒剩HTTP响应报文后,交给浏览器去渲染页面,一份特别
的数据包快递,就这样显示出来了!
最后,客户端要离开了,向服务器发起了TCP四次挥手,至此双方的连接就断开了。

参考资料

[1]2.2 键入网址到网页显示,期间发生了什么? | 小林coding (xiaolincoding.com)
[2]户根勤.网络是怎么连接的.人民邮电出版社

如果觉得本文对您有所帮助,可以支持下博主,一分也是缘分😊
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇