一  前言

  打开浏览器从输入网址到网页呈现在大家面前,背后到底发生了什么?经历怎么样的一个过程?先给大家来张总体流程图,具体步骤请看下文分解!

  

  从URL输入到页面展现

  总体来说分为以下几个过程:

  (1)URL 解析

  (2)DNS 解析:将域名解析成 IP 地址

  (3)TCP 连接:TCP 三次握手

  (4)发送 HTTP 请求

  (5)服务器处理请求并响应 HTTP 报文

  (6)浏览器解析渲染页面

  (7)断开连接:TCP 四次挥手

二  URL解析

  URL(Uniform Resource Locator),统一资源定位符,用于定位互联网上资源,俗称网址。比如 http://www.w3school.com.cn/html/index.asp,遵守以下的语法规则:

  scheme://host.domain:port/path/filename

  各部分解释如下:

    scheme - 定义因特网服务的类型。常见的协议有 http、https、ftp、file,其中最常见的类型是 http,而 https 则是进行加密的网络传输。

    host - 定义域主机(http 的默认主机是 www)

    domain - 定义因特网域名,比如 w3school.com.cn

    port - 定义主机上的端口号(http 的默认端口号是 80)

    path - 定义服务器上的路径(如果省略,则文档必须位于网站的根目录中)。

    filename - 定义文档/资源的名称

  解析流程如下:

    (1)地址解析:

      首先判断你输入的是一个合法的 URL 还是一个待搜索的关键词,并且根据你输入的内容进行自动完成、字符编码等操作。

    (2)HSTS

      由于安全隐患,会使用 HSTS 强制客户端使用 HTTPS 访问页面。

    (3)其他操作

      浏览器还会进行一些额外的操作,比如安全检查、访问限制(之前国产浏览器限制 996.icu)。

    (4)检查缓存

      

 

三  DNS域名解析

  在浏览器输入网址后,首先要经过域名解析,因为浏览器并不能直接通过域名找到对应的服务器,而是要通过 IP 地址。大家这里或许会有个疑问----计算机既可以被赋予 IP 地址,也可以被赋予主机名和域名。比如 www.hackr.jp。那怎么不一开始就赋予个 IP 地址?这样就可以省去解析麻烦。我们先来了解下什么是 IP 地址

1  IP 地址

  IP 地址是指互联网协议地址,是 IP Address 的缩写。IP 地址是 IP 协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。IP 地址是一个 32 位的二进制数,比如 127.0.0.1 为本机 IP。

  域名就相当于 IP 地址乔装打扮的伪装者,带着一副面具。它的作用就是便于记忆和沟通的一组服务器的地址。用户通常使用主机名或域名来访问对方的计算机,而不是直接通过 IP 地址访问。因为与 IP 地址的一组纯数字相比,用字母配合数字的表示形式来指定计算机名更符合人类的记忆习惯。但要让计算机去理解名称,相对而言就变得困难了。因为计算机更擅长处理一长串数字。为了解决上述的问题,DNS 服务应运而生。

2  什么是域名解析

  DNS 协议提供通过域名查找 IP 地址,或逆向从 IP 地址反查域名的服务。DNS 是一个网络服务器,我们的域名解析简单来说就是在 DNS 上记录一条信息记录

  例如 baidu.com 220.114.23.56(服务器外网IP地址)80(服务器端口号)

3  浏览器如何通过域名去查询 URL 对应的 IP 呢

  基本步骤如下:

   

  1. 浏览器缓存

    浏览器会先检查是否在缓存中,没有则调用系统库函数进行查询。浏览器会按照一定的频率缓存 DNS 记录。

  2. 操作系统缓存

    如果浏览器缓存中找不到需要的 DNS 记录,那就去操作系统中找。操作系统也有自己的 DNS缓存,但在这之前,会向检查域名是否存在本地的 Hosts 文件里,没有则向 DNS 服务器发送查询请求。

  3. 路由器缓存

    路由器也有自己的缓存。

  4. ISP DNS 缓存

    ISP 是互联网服务提供商(Internet Service Provider)的简称,ISP 有专门的 DNS 服务器应对 DNS 查询请求。ISP DNS 就是在客户端电脑上设置的首选 DNS 服务器,它们在大多数情况下都会有缓存。

  5. 根域名服务器查询

    ISP 的 DNS 服务器还找不到的话,它就会向根服务器发出请求,进行递归查询(DNS 服务器先问根域名服务器.com 域名服务器的 IP 地址,然后再问.baidu 域名服务器,依次类推)在前面所有步骤没有缓存的情况下,本地 DNS 服务器会将请求转发到互联网上的根域,下面这个图很好的诠释了整个流程:

   

4  小结

  浏览器通过向 DNS 服务器发送域名,DNS 服务器查询到与域名相对应的 IP 地址,然后返回给浏览器,浏览器再将 IP 地址打在协议上,同时请求参数也会在协议搭载,然后一并发送给对应的服务器。接下来介绍向服务器发送 HTTP 请求阶段,HTTP 请求分为三个部分:TCP 三次握手、http 请求响应信息、关闭 TCP 连接。

需要注意的点

  1. 递归方式:一路查下去中间不返回,得到最终结果才返回信息(浏览器到本地DNS服务器的过程)

  2. 迭代方式,就是本地DNS服务器到根域名服务器查询的方式。

  3. 什么是 DNS 劫持

  4. 前端 dns-prefetch 优化

四  建立连接

  在客户端发送数据之前需要发起 TCP 三次握手建立与服务端的连接,用以同步客户端和服务端的序列号和确认号,并交换 TCP 窗口大小信息。所谓三次握手(Three-way Handshake),是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。

1  TCP三次握手

  

  (1) 第一次握手:建立连接时,客户端A发送SYN包(SYN=1,同时选择一个初始序列号 seq=x )到服务器B,并进入SYN_SEND状态,等待服务器B确认。

  (2) 第二次握手:服务器B收到SYN包,必须确认客户A的SYN=1,同时自己也发送一个SYN包(SYN=1,确认号是ack=x+1,同时也要为自己初始化一个序列号 seq=y),即SYN+ACK包,此时服务器B进入SYN_RECV状态。

  (3) 第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ack=y+1,自己的序列号seq=Z),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成。

2  SYN攻击

  在三次握手过程中,服务器发送 SYN+ACK 之后,收到客户端的ACK之前的TCP连接称为半连接(half-open connect)。此时服务器处于Syn_RECV状态。当收到ACK后,服务器转入ESTABLISHED状态。

  Syn攻击就是攻击客户端在短时间内伪造大量不存在的IP地址,向服务器不断地发送syn包,服务器回复确认包,并等待客户的确认,由于源地址是不存在的,服务器需要不断的重发直 至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,目标系统运行缓慢,严重者引起网络堵塞甚至系统瘫痪。

  Syn攻击是一个典型的DDOS攻击。检测SYN攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。在Linux下可以如下命令检测是否被Syn攻击

  netstat -n -p TCP | grep SYN_RECV

  一般较新的TCP/IP协议栈都对这一过程进行修正来防范Syn攻击,修改tcp协议实现。主要方法有SynAttackProtect保护机制、SYN cookies技术、增加最大半连接和缩短超时时间等。但是不能完全防范syn攻击。

3  为什么不能用两次握手进行连接

  答:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。  

  如果把三次握手改成仅需要两次握手,死锁是可能发生的。如下图所示,如果计算机Client和Server之间的通信,假定Client给Server发送一个连接请求分组,Server收到了这个分组,并发送了确认应答分组。按照两次握手的协定,Server认为连接已经成功地建立了,可以开始发送数据分组。可是,Client在Server的应答分组在传输中被丢失的情况下,将不知道Server是否已准备好,不知道Server建立什么样的序列号,Client甚至怀疑Server是否收到自己的连接请求分组。在这种情况下,Client认为连接还未建立成功,将忽略Server发来的任何数据分组,Client只等待连接确认应答分组。而Server在发出的数据分组超时后,重复发送同样的数据分组。这样就形成了死锁

 

  另外三次握手可以防止已失效的连接请求报文段突然又传到了Server,因而产生错误。假定出现一种异常情况,即Client发出的第一个连接请求报文段并没有丢失,而是在某些网络结 点长时间滞留了,一直延迟到连接释放以后的某个时间才到达Server,本来这是一个早已失效的报文段。但Server收到此失效的连接请求报文段后,就误认为是Client又发出一次 新的连接请求,于是就向Client发出确认报文段,同意建立连接。假定不采用三次握手,那么只要Server发出确认,新的连接就建立了,这样一直等待Client发来数据,Server的许多资源就这样白白浪费了。

五  发送HTTP请求

1  请求报文介绍  

TCP 三次握手结束后,开始发送 HTTP 请求报文
  请求报文由请求行(request line)、请求头(header)、请求体三个部分组成,如下图所示

 

1. 请求行包含请求方法、URL、协议版本

  请求方法包含 8 种:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE。

  URL 即请求地址,由 <协议>://<主机>:<端口>/<路径>?<参数> 组成

  协议版本即 http 版本号

POST  /chapter17/user.html HTTP/1.1

  以上代码中“POST”代表请求方法,“/chapter17/user.html”表示 URL,“HTTP/1.1”代表协议和协议的版本。现在比较流行的是 Http1.1 版本

2. 请求头包含请求的附加信息,由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。

  请求头部通知服务器有关于客户端请求的信息。它包含许多有关的客户端环境和请求正文的有用信息。其中比如:Host,表示主机名,虚拟主机;Connection,HTTP/1.1 增加的,使用 keepalive,即持久连接,一个连接可以发多个请求;User-Agent,请求发出者,兼容性以及定制化需求。

3. 请求体,可以承载多个请求参数的数据,包含回车符、换行符和请求数据,并不是所有请求都具有请求数据。

name=tom&password=1234&realName=tomson

  上面代码,承载着 name、password、realName 三个请求参数。

2  请求流程

  TCP/IP 分为四层,在发送数据时,每层都要对数据进行封装: 

   

1.  应用层:发送 HTTP 请求

  在前面的步骤我们已经得到服务器的 IP 地址,浏览器会开始构造一个 HTTP 报文,其中需要注意的点:

    浏览器只能发送 GET、POST 方法,而打开网页使用的是 GET 方法

2. 传输层:TCP 传输报文

  传输层会发起一条到达服务器的 TCP 连接,为了方便传输,会对数据进行分割(以报文段为单位),并标记编号,方便服务器接受时能够准确地还原报文信息。

  在建立连接前,会先进行 TCP 三次握手。

3. 网络层:IP协议查询Mac地址

  将数据段打包,并加入源及目标的IP地址,并且负责寻找传输路线。判断目标地址是否与当前地址处于同一网络中,是的话直接根据 Mac 地址发送,否则使用路由表查找下一跳地址,以及使用 ARP 协议查询它的 Mac 地址。

4. 链路层:以太网协议

  以太网协议

    根据以太网协议将数据分为以“帧”为单位的数据包,每一帧分为两个部分:

      标头:数据包的发送者、接受者、数据类型

      数据:数据包具体内容

  Mac 地址

    以太网规定了连入网络的所有设备都必须具备“网卡”接口,数据包都是从一块网卡传递到另一块网卡,网卡的地址就是 Mac 地址。每一个 Mac 地址都是独一无二的,具备了一对一的能力。

  广播

    发送数据的方法很原始,直接把数据通过 ARP 协议,向本网络的所有机器发送,接收方根据标头信息与自身 Mac 地址比较,一致就接受,否则丢弃。

  注意:接收方回应是单播。

六  服务器处理请求并返回 HTTP 报文

   大致流程如下:

  

1.  服务器

  服务器是网络环境中的高性能计算机,它侦听网络上的其他计算机(客户机)提交的服务请求,并提供相应的服务,比如网页服务、文件下载服务、邮件服务、视频服务。而客户端主要的功能是浏览网页、看视频、听音乐等等,两者截然不同。 每台服务器上都会安装处理请求的应用——web server。常见的 web server 产品有 apache、nginx、IIS 或 Lighttpd 等。

  web server 担任管控的角色,对于不同用户发送的请求,会结合配置文件,把不同请求委托给服务器上处理相应请求的程序进行处理(例如 CGI 脚本,JSP 脚本,servlets,ASP 脚本,服务器端 JavaScript,或者一些其它的服务器端技术等),然后返回后台程序处理产生的结果作为响应。

   
          服务器和客户端区别.png

2. MVC 后台处理阶段

  后台开发现在有很多框架,但大部分都还是按照 MVC 设计模式进行搭建的。MVC 是一个设计模式,将应用程序分成三个核心部件:模型(model)-- 视图(view)--控制器(controller),它们各自处理自己的任务,实现输入、处理和输出的分离。

  简而言之,首先浏览器发送过来的请求先经过控制器,控制器进行逻辑处理和请求分发,接着会调用模型,这一阶段模型会获取 redis db 以及 MySQL 的数据,获取数据后将渲染好的页面,响应信息会以响应报文的形式返回给客户端,最后浏览器通过渲染引擎将网页呈现在用户面前。

3. HTTP响应报文

  响应报文由响应行(request line)、响应头部(header)、响应主体三个部分组成。如下图所示:

   

  (1) 响应行包含:协议版本,状态码,状态码描述

    状态码规则如下:
      1xx:指示信息--表示请求已接收,继续处理。

      2xx:成功--表示请求已被成功接收、理解、接受。

      3xx:重定向--要完成请求必须进行更进一步的操作。

      4xx:客户端错误--请求有语法错误或请求无法实现。

      5xx:服务器端错误--服务器未能实现合法的请求。

  (2) 响应头部包含响应报文的附加信息,由 名/值 对组成

  (3) 响应主体包含回车符、换行符和响应返回数据,并不是所有响应报文都有响应数据

七  浏览器解析渲染页面

  浏览器拿到响应文本 HTML 后,接下来介绍下浏览器渲染机制

  

  浏览器解析渲染页面分为一下五个步骤:

    根据 HTML 解析出 DOM 树

    根据 CSS 解析生成 CSS 规则树

    结合 DOM 树和 CSS 规则树,生成渲染树

    根据渲染树计算每一个节点的信息

    根据计算好的信息绘制页面

1  根据 HTML 解析 DOM 树

  根据 HTML 的内容,将标签按照结构解析成为 DOM 树,DOM 树解析的过程是一个深度优先遍历。即先构建当前节点的所有子节点,再构建下一个兄弟节点。

  在读取 HTML 文档,构建 DOM 树的过程中,若遇到 script 标签,则 DOM 树的构建会暂停,直至脚本执行完毕。

2  根据 CSS 解析生成 CSS 规则树

  解析 CSS 规则树时 js 执行将暂停,直至 CSS 规则树就绪。

  浏览器在 CSS 规则树生成之前不会进行渲染。

3  结合 DOM 树和 CSS 规则树,生成渲染树

  DOM 树和 CSS 规则树全部准备好了以后,浏览器才会开始构建渲染树。

  精简 CSS 并可以加快 CSS 规则树的构建,从而加快页面相应速度。

4  根据渲染树计算每一个节点的信息(布局)

  布局:通过渲染树中渲染对象的信息,计算出每一个渲染对象的位置和尺寸

  回流:在布局完成后,发现了某个部分发生了变化影响了布局,那就需要倒回去重新渲染。

5  根据计算好的信息绘制页面

  绘制阶段,系统会遍历呈现树,并调用呈现器的“paint”方法,将呈现器的内容显示在屏幕上。

  重绘:某个元素的背景颜色,文字颜色等,不影响元素周围或内部布局的属性,将只会引起浏览器的重绘。

  回流:某个元素的尺寸发生了变化,则需重新计算渲染树,重新渲染。

八  断开连接

1  四次挥手

  当数据传送完毕,需要断开 tcp 连接,此时发起 tcp 四次挥手。TCP的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake)。客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close()操作即可产生挥手操作。

  

  (1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。发起方向被动方发送报文,Fin、Ack、Seq,表示已经没有数据传输了。并进入 FIN_WAIT_1 状态。(第一次挥手:由浏览器发起的,发送给服务器,我请求报文发送完了,你准备关闭吧)

  (2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。被动方发送确认报文,Ack、Seq,表示同意关闭请求。此时主动发起方进入 FIN_WAIT_2 状态。(第二次挥手:由服务器发起的,告诉浏览器,我请求报文接受完了,我准备关闭了,你也准备吧)

  (3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。被动方向发起方发送报文段,Fin、Ack、Seq,请求关闭连接。并进入 LAST_ACK 状态。(第三次挥手:由服务器发起,告诉浏览器,我响应报文发送完了,你准备关闭吧)

  (4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。发起方向被动方发送报文段,Ack、Seq。然后进入等待 TIME_WAIT 状态。被动方收到发起方的报文段以后关闭连接。发起方等待一定时间2MSL未收到回复,则正常关闭。(第四次挥手:由浏览器发起,告诉服务器,我响应报文接受完了,我准备关闭了,你也准备吧)

2  为什么连接的时候是三次握手,关闭的时候却是四次握手?

  答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。

  只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

3  为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

  答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。

  所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。

  MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

 

参考

  https://www.cnblogs.com/geoffreyone/p/10021290.html

  https://mp.weixin.qq.com/s/aB6vQ0AmE_bmPZnD_5K59Q

posted on 2019-09-07 15:03  Vagrant。  阅读(1796)  评论(0编辑  收藏  举报