08_键入网址再按下回车,后面究竟发生了什么?

内容

  1. 在www目录下,运行start批处理程序,启动本机的Openr服务器,启动后可以用List批处理确认服务是否正常运行
  2. 打开wireshark,选择TCP port HTTP过滤器,再鼠标双击Npcap Loopback Adapter,开始抓取本机127.0.0.1地址上的网络数据
  3. 在chrome浏览器的地址栏,输入Http://127.0.0.1/,再按下回车键,等欢迎页面显示出来之后,wireshark里就会有捕获的数据包
08_键入网址再按下回车,后面究竟发生了什么?_第1张图片
使用IP地址访问web服务器

抓包分析

在wireshark里,可以看到11个包(因为用了滤包功能,滤掉了3个包,原本是14个包),基于此,来分析来,键入网址按下回车之后的数据传输全过程。
通过前面的讲解,能知道HTTP协议是运行在TCP/IP基础上的,依靠TCP/IP协议来实现数据的可靠传输。所以浏览器要用HTTP协议收发数据,首先要做就是建立TCP链接。

因为,在地址栏里直接输入了IP地址,“127.0.0.1”,而web服务器的默认端口是80,所以浏览器就要依照TCP协议的规范,使用三次握手建立与web服务器的连接。对应到wireshark里,就是最开始的三个抓包,浏览器使用的端口是52085,服务器使用的端口是80,经过SYN、SYN/ACK、ACK的三个抓包后,浏览器与服务器的TCP连接就建立起来了。

有了可靠的TCP连接通道后,HTTP协议就开始工作了。于是,浏览器按照HTTP协议规定的格式,通过TCP发送了一个“GET/HTTP/1.1”请求报文,也就是Wireshark里的第四个包。至于包的具体内容,可以之后再说。

随后,Web服务器回复了第五个包,在TCP协议层面确认:刚才的报文我已经收到了,不过这个TCP包HTTP协议是看不见的。

web服务器收到报文后,在内部就要处理这个请求,同样也是依据HTTP协议的规定,解析报文,看看这个浏览器发送这个请求想要干什么。

他一,原来是要求获取根目录下的默认文件,那就从磁盘上把那个文件全读出来,再拼成符合HTTP格式的报文,发回去。这个就是Wireshark里的第六个包,“HTTP/1.1 200OK”, 底层走的还是TCP协议。

同样的,浏览器也要给服务器回复一个TCP的ACK确认,“你的响应报文收到了,多谢”,即第七个包。这时,浏览器就收到了相应数据,但里面是什么呢?所以也要解析报文,一看,服务器给我的是HTML文件,那好,那我就调用排版引擎、JS引擎来处理一下,然后再浏览器窗口展现出了欢迎页面。

这之后,还有两个来回,共四个包,重复了相同的步骤。这时浏览器自动请求了作为网站图标的“favicon.ico”文件,与我们的输入网址无关。但因为我们的实验环境没有这个文件,所以服务器在硬盘上找不到,返回了一个“404,not found”。

至此,键入网址再按下回车的全过程就结束了,下图为交互图纸。不过,图里TCP关闭连接的四次挥手,在抓包里没有出现,这是因为HTTP/1/1厂连接特性,默认不会立即关闭连接。

HTTP的三次抓包+四次挥手

叙述全过程:

  1. 浏览器从地址栏的输入中获得服务器的IP地址和端口号
  2. 浏览器用TCP的三次握手与服务器建立连接
  3. 浏览器向服务器发送拼好的报文
  4. 服务器收到报文后处理请求,同样拼好报文再发送给浏览器
  5. 浏览器解析报文,渲染输出页面

使用域名访问web服务器

刚才我们是在浏览器地址里直接输入IP地址,但在绝大多数情况下,我们是不知道服务器IP地址的,使用的是域名,那么改用域名后,这个过程会有什么不同吗?
实际动手试下吧,把地址栏的输入改成:“www.chrono.com”,重复wiresh抓包过程,会发现,好像没有什么不同,浏览器上同样显示出了欢迎界面,抓到的包也同样是11
个,先是三次握手,然后是两次HTTP传输。

这里就出现了一个问题:浏览器是如何从网址里知道,"www.chrono.com"的IP地址就是“127.0.0.1”的呢?

像是之前写过的DNS内容,当浏览器看到了网址的"www.chrono.com",发现他不是数字形式的IP地址,那就肯定是域名了,于是就会发起域名解析动作,通过访问一系列的域名解析服务器,试图把这个域名翻译成TCP/IP协议里的IP地址。不过因为域名解析的全过程实在是太复杂了,如果每一个域名都要大费周折地去网上查一下,那上网肯定会慢得受不了。

所以,在域名解析的过程中会有多级的缓存,浏览器首先看一下自己的缓存里有没有,如果没有就向操作系统的缓存要,还没有就检查本机域名解析文件hosts。如果hosts文件里有,那浏览器就知道了域名对应的IP地址,就可以愉快地建立TCP连接发送HTTP请求了。图里的浏览器多出了一个访问hosts文件的动作,这也就是本机的DNS解析。


08_键入网址再按下回车,后面究竟发生了什么?_第2张图片
域名解析

真实的网络世界

在两个最小化环境的实验里,
第一个实验是最简单的场景,只有两个角色:浏览器和服务器,浏览器可以直接用IP地址找到服务器,两者直接建立TCP连接后发送HTTP报文通信。
第二个实验是在浏览器和服务器之外,增加了一个DNS的角色,浏览器不知道服务器的IP地址,所以必须借助DNS的域名解析功能得到服务器的IP地址,然后才能与服务器通信。

真实的互联网场景要比这两个场景复杂得多,下图可以做个详细说明。


08_键入网址再按下回车,后面究竟发生了什么?_第3张图片
复杂场景

如果用的是电脑台式机,那么可能会是用带水晶头的双绞线连上网口,由交换机接入固定网络。如果用的是手机、平板电脑,那么可能就会通过蜂窝网络、wifi,由电信基站、无线热点接入移动网络。

接入网络的同时,网络运行商会给你的设备分配一个IP地址,这个地址可能是静态分配的,也可能是动态分配的。静态IP就始终不变,而动态IP可能下次上网就变了。

假设,要访问的是Apple网站,显然你是不知道他的真实IP地址的,在浏览器里只能使用域名“www.apple.com”访问,那么接下来要做的必然是域名解析。这就要用DNS协议开始从操作系统、本地DNS、根DNS、顶级DNS、权威DNS的层层解析,当然这中间可能会有缓存,所以可能不会费太多时间就能拿到结果。

这时候,互联网上还有一个重要的角色CDN,他也会在DNS的解析过程中插上一脚。DNS解析可能会给出CDN服务器的IP地址,这样拿到的就会是CDN服务器,而不是目标网站的实际地址。因为CDN会缓存网站的大部分资源,比如图片、CSS样式表,所以有的HTTP请求就不需要再发到APPLE,CDN就可以直接响应请求,把数据发过来。

由PHP、Java等后台服务动态生成的页面,属于动态资源,CDN无法缓存,只能从目标网站获取。于是,浏览器发出的HTTP请求,就要开始在互联网上进行长途跋涉,经过无数的路由器、网关、代理,达到最后的目的地。

目标网站的服务器对外表现的是一个IP地址,但为了能够扛住高并发,在内部也是一套复杂的架构。通常在入口是负载均衡设备,例如四层的LVS或者七层的Nginx,在后面是许多的服务器,构成一个更强更稳定的集群。

负载均衡设备会县访问系统里的缓存服务器,通常有memory级换成Redis和dis级缓存Varnish,他们的作用与CDN类似,不过是工作在内部网络,把最频繁访问的数据缓存几秒钟或几分钟,减轻后端应用服务器的压力。

如果缓存服务器里也没有,那么负载均衡设备就要把请求转发给应用服务器了。这里就是各种开发框架大显神通的地方了,例如Java的Tomcat/Netty/Jetty,python的Django,还有PHP、Node.js、Goland等等。他们又会再访问后面的MySQL、PostgreSQL、MongoDB等数据库服务,实现用户登录、商品查询、购物下单、扣款支付等业务操作,然后把执行的结果返回给负载均衡设备,同时也可能给缓存服务器里也放一份。

应用服务器的输出到了负载均衡设备这里,请求的处理就算是完成了,就要按照原路再走回去,还是要经过许多的路由器、网关、代理。如果这个资源允许缓存,那么经过CDN的时候,他也会做缓存,这样下次同样的请求就不会到达源站了。

最后网站的响应数据回到了设备上,他可能是HTML、JSON、图片或者其他格式的数据,需要由浏览器解析处理才能显示出来。如果数据里还有超链接,指向别的资源,那么就要重走一遍整个流程,直到把所有的资源都下载完。

小结

  1. HTTP协议基于底层的TCP/IP协议,所以必须要用IP地址建立连接
  2. 如果不知道IP地址,就要用DNS协议去解析得到IP地址,否则就会连接失败
  3. 建立TCP连接后会顺序收发数据,请求方和应答方都必须依据HTTP规范构建和解析报文
  4. 为了减少响应时间,整个过程中的每一个环节都会有缓存,能够实现“短路”操作
  5. 虽然现实中的HTTP传输过程非常复杂,但理论上仍然可以简化成实验室里的两点模型

你可能感兴趣的:(08_键入网址再按下回车,后面究竟发生了什么?)