虽然你只是按下了回车,但这中间的事太多

一个经典问题引发的思考:
“一个优秀的程序员必须有足够的网络姿势和数据库姿势,来,你说说当你在浏览器中输入“http://www.expruan.site”后发生了什么?”
“面试官,这个域名解析失败,好像什么都没发生?”
“连域名都不续费,你先等通知吧”

一个经典问题

“当我们在浏览器的地址栏中输入网址并按下回车时,直至web页面显示时,这中间发生了什么?”
这是一个经典的问题,大致过程可以认为是:
1、DNS将域名解析为IP地址并回传给客户端;
2、通过三次握手建立TCP连接;
3、客户端发送HTTP请求,HTTP协议生成针对目标web的HTTP报文,TCP协议将上述报文按序号分割成多个报文段,把每个报文段传送给对方;
4、IP协议:一边中转一边传送;
5、TCP协议将报文段重组为报文,HTTP协议对web服务器请求的内容处理,请求结果利用TCP/IP通信协议回传;
6、浏览器接受服务器资源渲染web页面;
7、四次挥手断开连接。

日常五连问:它从哪来,为什么来,到哪去,怎么去,要干嘛?

按下回车

作为一个电信的科班生,看到这个问题的第一反应是键盘上回车键所对应的电流开关闭合,某位管脚置为0。系统将读入的管脚信息转化为键盘码值,用于之后的传输。

生成HTTP请求

鉴于我自己的域名过期了,此处以www.baidu.com/index.html为例。
首先,浏览器会根据URL中的http知道我们要访问的服务器是web服务器,www.baidu.com是web服务器的名字,index.htm是数据源路径/文件名。
根据上述的解析生成http请求消息:

GET /index.html HTTP/1.1 <!-- 请求行 -->
User-Agent: Mozilla/5.0
Host: www.baidu.com
Accept: */*
<!-- 空行 -->

发送请求后,会得到服务器的响应消息(简化):

HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: keep-alive
Content-Length: 2443
Content-Type: text/html<!-- 空行 -->

<html>
    <!-- 网页信息-->
</html>

浏览器生成了HTTP请求后,需要操作系统来把数据发送出去,内核协议栈用的是IP,并不是域名,所以要进行域名(DNS)解析。web浏览器中通过函数gethostbyname (“www.baidu.com”),获取IP。

gethostbyname()函数内部实现就是生成DNS查询消息,发送UDP查询消息到DNS服务器,得到DNS服务器的响应,从响应消息中取出IP。

这里需要注意,我们要去DNS服务器查询信息,需要知道DNS服务器的IP地址,这就牵扯到DNS的配置问题,此处不赘述。

DNS解析过程

DNS解析的过程就是寻找哪台机器上有你需要资源的过程,寻找的过程遵循就近原则。在DNS解析开始之前,必须要回想一下根DNS服务器、顶级DNS服务器和权威DNS服务器,三者之间的关系如下:
在这里插入图片描述

当输入一个网址并按回车的时候浏览器会根据输入的URL去查找对应的IP过程应当是:
(1)首先是查找浏览器缓存,浏览器会保存一段时间内访问过的一些网址的DNS信息,不同浏览器保存的时常不等,以chrome为例,你可以在地址栏输入:chrome://net-internals/#dns来查询自己曾经访问过的网站;
(2)如果没有找到对应的记录,这个时候浏览器会尝试调用操作系统缓存(host文件)来继续查找这个网址的对应DNS信息;
(3)如果还是没找到对应的IP,那么接着会发送一个请求到路由器上,然后路由器在自己的路由器缓存上查找记录,路由器一般也存有DNS信息;
(4)如果还是没有,这个请求就会被发送到ISP(注:Internet Service Provider,互联网服务提供商,就是网络运营商,中国电信中国移动等),ISP也会有相应的ISP DNS服务器,就是本地DNS服务器,请求的域名基本上都能在这里找得到;
(5)如果还是没有的话, ISP的DNS服务器会将请求发向域名服务器进行搜索,它告诉(com)服务器地址。根域名服务器就是面向全球的顶级DNS服务器,共有13台逻辑上的服务器,从A到M命名,真正的实体服务器则有几百台,分布于全球各大洲(话说为啥是13台??这其实是个蛮有趣的故事,可参考https://www.zhihu.com/question/22587247);
(6)comDNS服务器注意到其baidu.com后缀并用负责该域名的权威DNS服务器的IP地址作为回应;
(6)如果到了这里还是找不到域名的对应信息,那只能说明一个问题:这个域名本来就不存在,它没有在网上正式注册过。或者域名过期了(是的,你的没续费的域名)。
这也就是为什么有时候打开一个新页面会有点慢,因为如果本地没什么缓存,查找域名的过程要这样递归地查询下去,查找完还要一层层的向上返回。

注意:严格来说本地DNS缓存并不属于DNS服务器的层次结构

所以DNS根据域名查询IP地址的过程为: 浏览器缓存 --> 操作系统缓存 --> 路由器缓存–>本地(ISP)域名服务器缓存 --> 根域名服务器。
当然,域名和ip也并非一一对应的关系,一个ip可以绑定多个域名,一个域名也可以定位多个ip(重定向)。
当浏览器得到了目标服务器的IP地址,以及URL中给出来端口号(http协议默认端口号是80, https默认端口号是443),它会委托内核调用 socket ,请求一个TCP流套接字 :

int fd = socket(AF_INET, SOCK_STREAM, 0);
connect(fd, 服务器地址);
while ( 1 ) {
    write(fd, http请求数据);
    read(fd,服务器响应的数据)
}
close(fd)

上述请求首先被交给传输层,在传输层请求被封装成TCP segment。目标端口会会被加入头部,源端口会在系统内核的动态端口范围内选取(Linux下是ip_local_port_range)
TCP segment被送往网络层,网络层会在其中再加入一个IP头部,里面包含了目标服务器的IP地址以及本机的IP地址,把它封装成一个TCP packet。
这个TCP packet接下来会进入链路层,链路层会在封包中加入frame头部,里面包含了本地内置网卡的MAC地址以及网关(本地路由器)的MAC地址。像前面说的一样,如果内核不知道网关的MAC地址,它必须进行ARP广播来查询其地址。
至此,我们的封包就好了,然后将其以010101010的数据流形式(帧)~传输!

ARP做了什么

ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址。

在网络访问层中,同一局域网中的一台主机要和另一台主机进行通信,需要通过 MAC
地址进行定位,然后才能进行数据包的发送。而在网络层和传输层中,计算机之间是通过 IP 地址定位目标主机,对应的数据报文只包含目标主机的 IP地址,而没有 MAC 地址。 因此,在发送数据包之前需要根据 IP 地址获取 MAC地址,然后才能将数据包发送到正确的目标主机,这一过程是ARP 协议完成的。

上述的DNS查询过程中如果DNS服务器和当前请求主机在同一个子网内,那么将会对 DNS 服务器进行 ARP查询,如果DNS服务器和当前主机在不同的子网,系统使用ARP 过程对默认网关进行查询。

  1. 这一过程中首先查询ARP缓存,如果缓存命中,我们返回结果:目标IP = MAC;
  2. 如果本地无缓存则查看路由表,看看目标IP地址是不是在本地路由表中的某个子网内。是的话,使用跟那个子网相连的接口,否则使用与默认网关相连的接口。
  3. 查询选择的网络接口的MAC地址
  4. 发送ARP请求得到ARP Reply ,类似于:
`ARP Reply:
Sender MAC: target:mac:address:here
Sender IP: target.ip.goes.here
Target MAC: interface:mac:address:here
Target IP: interface.ip.goes.here`

在得到DNS服务器或者默认网关的IP地址后就可以继续DNS请求了~

内核协议栈做了哪些事情

因为HTTP协议底层用的是TCP协议,所以通过DNS服务器解析后获得了网址的IP地址后,浏览器会向域名对应的IP地址服务器发起TCP连接,即发起HTTP“三次握手”。即这个tcp连接请求要经过层层的路由设备到达服务器端以后进入到网卡,一路上经过的这些路由器会从IP数据报头部里提取出目标地址,并将封包正确地路由到下一个目的地。之后进入到内核的TCP/IP协议栈,还有可能要经过防火墙的过滤,最终到达Web服务端,然后建立起TCP/IP的连接,传送数据,最后四次挥手断开连接。(IP数据报头部TTL域的值每经过一个路由器就减1,如果封包的TTL变为0,或者路由器由于网络拥堵等原因封包队列满了,那么这个包会被路由器丢弃。)
(三次握手和四次挥手的故事下次在讲吧)

服务器做了哪些事情

目标服务器得到了客户端的HTTP请求,对该请求进行解析,如果找到相应的资源文件,组成HTTP响应报文(响应头+响应),将资源发送回来,响应头中包含了Stauus code(2xx,3xx,4xx),响应就是具体的页面编码。浏览器接收到响应后对页面进行渲染。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值