UDP 是一个面向报文(报文能够理解为一段段的数据)的协议。意思就是 UDP 只是报文的搬运工,不会对报文进行任何拆分和拼接操做。web
具体来讲面试
由于 UDP 没有 TCP 那么复杂,须要保证数据不丢失且有序到达。因此 UDP 的头部开销小,只有八字节,相比 TCP 的至少二十字节要少得多,在传输数据报文时是很高效的。算法
头部包含了如下几个数据浏览器
UDP 不止支持一对一的传输方式,一样支持一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播,广播的功能。缓存
TCP 头部比 UDP 头部复杂的多安全
对于 TCP 头部来讲,如下几个字段是很重要的服务器
HTTP 是无链接的,因此做为下层的 TCP 协议也是无链接的,虽然看似 TCP 将两端链接了起来,可是其实只是两端共同维护了一个状态cookie
TCP 的状态机是很复杂的,而且与创建断开链接时的握手息息相关,接下来就来详细描述下两种握手。网络
在这以前须要了解一个重要的性能指标 RTT。该指标表示发送端发送数据到接收到对端数据所需的往返时间。并发
在 TCP 协议中,主动发起请求的一端为客户端,被动链接的一端称为服务端。无论是客户端仍是服务端,TCP 链接创建完后都能发送和接收数据,因此 TCP 也是一个全双工的协议。
起初,两端都为 CLOSED 状态。在通讯开始前,双方都会建立 TCB。 服务器建立完 TCB 后遍进入 LISTEN 状态,此时开始等待客户端发送数据。
第一次握手
客户端向服务端发送链接请求报文段。该报文段中包含自身的数据通信初始序号。请求发送后,客户端便进入 SYN-SENT 状态,x
表示客户端的数据通讯初始序号。
第二次握手
服务端收到链接请求报文段后,若是赞成链接,则会发送一个应答,该应答中也会包含自身的数据通信初始序号,发送完成后便进入 SYN-RECEIVED 状态。
第三次握手
当客户端收到链接赞成的应答后,还要向服务端发送一个确认报文。客户端发完这个报文段后便进入ESTABLISHED 状态,服务端收到这个应答后也进入 ESTABLISHED 状态,此时链接创建成功。
PS:第三次握手能够包含数据,经过 TCP 快速打开(TFO)技术。其实只要涉及到握手的协议,均可以使用相似 TFO 的方式,客户端和服务端存储相同 cookie,下次握手时发出 cookie 达到减小 RTT 的目的。
你是否有疑惑明明两次握手就能够创建起链接,为何还须要第三次应答?
由于这是为了防止失效的链接请求报文段被服务端接收,从而产生错误。
能够想象以下场景。客户端发送了一个链接请求 A,可是由于网络缘由形成了超时,这时 TCP 会启动超时重传的机制再次发送一个链接请求 B。此时请求顺利到达服务端,服务端应答完就创建了请求。若是链接请求 A 在两端关闭后终于抵达了服务端,那么这时服务端会认为客户端又须要创建 TCP 链接,从而应答了该请求并进入 ESTABLISHED 状态。此时客户端实际上是 CLOSED 状态,那么就会致使服务端一直等待,形成资源的浪费。
PS:在创建链接中,任意一端掉线,TCP 都会重发 SYN 包,通常会重试五次,在创建链接中可能会遇到 SYN FLOOD 攻击。遇到这种状况你能够选择调低重试次数或者干脆在不能处理的状况下拒绝请求。
TCP 是全双工的,在断开链接时两端都须要发送 FIN 和 ACK。
第一次握手
若客户端 A 认为数据发送完成,则它须要向服务端 B 发送链接释放请求。
第二次握手
B 收到链接释放请求后,会告诉应用层要释放 TCP 连接。而后会发送 ACK 包,并进入 CLOSE_WAIT 状态,表示 A 到 B 的链接已经释放,不接收 A 发的数据了。可是由于 TCP 链接时双向的,因此 B 仍旧能够发送数据给 A。
第三次握手
B 若是此时还有没发完的数据会继续发送,完毕后会向 A 发送链接释放请求,而后 B 便进入 LAST-ACK 状态。
PS:经过延迟确认的技术(一般有时间限制,不然对方会误认为须要重传),能够将第二次和第三次握手合并,延迟 ACK 包的发送。
第四次握手
A 收到释放请求后,向 B 发送确认应答,此时 A 进入 TIME-WAIT 状态。该状态会持续 2MSL(最大段生存期,指报文段在网络中生存的时间,超时会被抛弃) 时间,若该时间段内没有 B 的重发请求的话,就进入 CLOSED 状态。当 B 收到确认应答后,也便进入 CLOSED 状态。
为何 A 要进入 TIME-WAIT 状态,等待 2MSL 时间后才进入 CLOSED 状态?
为了保证 B 能收到 A 的确认应答。若 A 发完确认应答后直接进入 CLOSED 状态,若是确认应答由于网络问题一直没有到达,那么会形成 B 不能正常关闭。
ARQ 协议也就是超时重传机制。经过确认和超时机制保证了数据的正确送达,ARQ 协议包含中止等待 ARQ 和连续 ARQ
正常传输过程
只要 A 向 B 发送一段报文,都要中止发送并启动一个定时器,等待对端回应,在定时器时间内接收到对端应答就取消定时器并发送下一段报文。
报文丢失或出错
在报文传输的过程当中可能会出现丢包。这时候超过定时器设定的时间就会再次发送丢包的数据直到对端响应,因此须要每次都备份发送的数据。
即便报文正常的传输到对端,也可能出如今传输过程当中报文出错的问题。这时候对端会抛弃该报文并等待 A 端重传。
PS:通常定时器设定的时间都会大于一个 RTT 的平均时间。
ACK 超时或丢失
对端传输的应答也可能出现丢失或超时的状况。那么超过定时器时间 A 端照样会重传报文。这时候 B 端收到相同序号的报文会丢弃该报文并重传应答,直到 A 端发送下一个序号的报文。
在超时的状况下也可能出现应答很迟到达,这时 A 端会判断该序号是否已经接收过,若是接收过只须要丢弃应答便可。
这个协议的缺点就是传输效率低,在良好的网络环境下每次发送报文都得等待对端的 ACK 。
在连续 ARQ 中,发送端拥有一个发送窗口,能够在没有收到应答的状况下持续发送窗口内的数据,这样相比中止等待 ARQ 协议来讲减小了等待时间,提升了效率。
连续 ARQ 中,接收端会持续不断收到报文。若是和中止等待 ARQ 中接收一个报文就发送一个应答同样,就太浪费资源了。经过累计确认,能够在收到多个报文之后统一回复一个应答报文。报文中的 ACK 能够用来告诉发送端这个序号以前的数据已经所有接收到了,下次请发送这个序号 + 1的数据。
可是累计确认也有一个弊端。在连续接收报文时,可能会遇到接收到序号 5 的报文后,并未接到序号 6 的报文,然而序号 7 之后的报文已经接收。遇到这种状况时,ACK 只能回复 6,这样会形成发送端重复发送数据,这种状况下能够经过 Sack 来解决,这个会在下文说到。
在上面小节中讲到了发送窗口。在 TCP 中,两端都维护着窗口:分别为发送端窗口和接收端窗口。
发送端窗口包含已发送但未收到应答的数据和能够发送可是未发送的数据。
发送端窗口是由接收窗口剩余大小决定的。接收方会把当前接收窗口的剩余大小写入应答报文,发送端收到应答后根据该值和当前网络拥塞状况设置发送窗口的大小,因此发送窗口的大小是不断变化的。
当发送端接收到应答报文后,会随之将窗口进行滑动
滑动窗口实现了流量控制。接收方经过报文告知发送方还能够发送多少数据,从而保证接收方可以来得及接收数据。
在发送报文的过程当中,可能会遇到对端出现零窗口的状况。在该状况下,发送端会中止发送数据,并启动 persistent timer 。该定时器会定时发送请求给对端,让对端告知窗口大小。在重试次数超过必定次数后,可能会中断 TCP 连接。
拥塞处理和流量控制不一样,后者是做用于接收方,保证接收方来得及接受数据。而前者是做用于网络,防止过多的数据拥塞网络,避免出现网络负载过大的状况。
拥塞处理包括了四个算法,分别为:慢开始,拥塞避免,快速重传,快速恢复。
慢开始算法,顾名思义,就是在传输开始时将发送窗口慢慢指数级扩大,从而避免一开始就传输大量数据致使网络拥塞。
慢开始算法步骤具体以下
拥塞避免算法相比简单点,每过一个 RTT 窗口大小只加一,这样可以避免指数级增加致使网络拥塞,慢慢将大小调整到最佳值。
在传输过程当中可能定时器超时的状况,这时候 TCP 会认为网络拥塞了,会立刻进行如下步骤:
快速重传通常和快恢复一块儿出现。一旦接收端收到的报文出现失序的状况,接收端只会回复最后一个顺序正确的报文序号(没有 Sack 的状况下)。若是收到三个重复的 ACK,无需等待定时器超时再重发而是启动快速重传。具体算法分为两种:
TCP Taho 实现以下
TCP Reno 实现以下
TCP New Reno 算法改进了以前 TCP Reno 算法的缺陷。在以前,快恢复中只要收到一个新的 ACK 包,就会退出快恢复。
在 TCP New Reno 中,TCP 发送方先记下三个重复 ACK 的分段的最大序号。
假如我有一个分段数据是 1 ~ 10 这十个序号的报文,其中丢失了序号为 3 和 7 的报文,那么该分段的最大序号就是 10。发送端只会收到 ACK 序号为 3 的应答。这时候重发序号为 3 的报文,接收方顺利接收并会发送 ACK 序号为 7 的应答。这时候 TCP 知道对端是有多个包未收到,会继续发送序号为 7 的报文,接收方顺利接收并会发送 ACK 序号为 11 的应答,这时发送端认为这个分段接收端已经顺利接收,接下来会退出快恢复阶段。
HTTP 协议是个无状态协议,不会保存状态。
先引入反作用和幂等的概念。
反作用指对服务器上的资源作改变,搜索是无反作用的,注册是反作用的。
幂等指发送 M 和 N 次请求(二者不相同且都大于 1),服务器上资源的状态一致,好比注册 10 个和 11 个账号是不幂等的,对文章进行更改 10 次和 11 次是幂等的。
在规范的应用场景上说,Get 多用于无反作用,幂等的场景,例如搜索关键字。Post 多用于反作用,不幂等的场景,例如注册。
在技术上说:
2XX 成功
3XX 重定向
4XX 客户端错误
5XX 服务器错误
通用字段 | 做用 |
---|---|
Cache-Control | 控制缓存的行为 |
Connection | 浏览器想要优先使用的链接类型,好比 keep-alive |
Date | 建立报文时间 |
Pragma | 报文指令 |
Via | 代理服务器相关信息 |
Transfer-Encoding | 传输编码方式 |
Upgrade | 要求客户端升级协议 |
Warning | 在内容中可能存在错误 |
请求字段 | 做用 |
---|---|
Accept | 能正确接收的媒体类型 |
Accept-Charset | 能正确接收的字符集 |
Accept-Encoding | 能正确接收的编码格式列表 |
Accept-Language | 能正确接收的语言列表 |
Expect | 期待服务端的指定行为 |
From | 请求方邮箱地址 |
Host | 服务器的域名 |
If-Match | 两端资源标记比较 |
If-Modified-Since | 本地资源未修改返回 304(比较时间) |
If-None-Match | 本地资源未修改返回 304(比较标记) |
User-Agent | 客户端信息 |
Max-Forwards | 限制可被代理及网关转发的次数 |
Proxy-Authorization | 向代理服务器发送验证信息 |
Range | 请求某个内容的一部分 |
Referer | 表示浏览器所访问的前一个页面 |
TE | 传输编码方式 |
响应字段 | 做用 |
---|---|
Accept-Ranges | 是否支持某些种类的范围 |
Age | 资源在代理缓存中存在的时间 |
ETag | 资源标识 |
Location | 客户端重定向到某个 URL |
Proxy-Authenticate | 向代理服务器发送验证信息 |
Server | 服务器名字 |
WWW-Authenticate | 获取资源须要的验证信息 |
实体字段 | 做用 |
---|---|
Allow | 资源的正确请求方式 |
Content-Encoding | 内容的编码格式 |
Content-Language | 内容使用的语言 |
Content-Length | request body 长度 |
Content-Location | 返回数据的备用地址 |
Content-MD5 | Base64加密格式的内容 MD5检验值 |
Content-Range | 内容的位置范围 |
Content-Type | 内容的媒体类型 |
Expires | 内容的过时时间 |
Last_modified | 内容的最后修改时间 |
PS:缓存相关已在别的模块中写完,你能够 阅读该小节
HTTPS 仍是经过了 HTTP 来传输信息,可是信息经过 TLS 协议进行了加密。
TLS 协议位于传输层之上,应用层之下。首次进行 TLS 协议传输须要两个 RTT ,接下来能够经过 Session Resumption 减小到一个 RTT。
在 TLS 中使用了两种加密技术,分别为:对称加密和非对称加密。
对称加密:
对称加密就是两边拥有相同的秘钥,两边都知道如何将密文加密解密。
非对称加密:
有公钥私钥之分,公钥全部人均可以知道,能够将数据用公钥加密,可是将数据解密必须使用私钥解密,私钥只有分发公钥的一方才知道。
TLS 握手过程以下图:
[图片上传失败...(image-9e840c-1543831239746)]
经过以上步骤可知,在 TLS 握手阶段,两端使用非对称加密的方式来通讯,可是由于非对称加密损耗的性能比对称加密大,因此在正式传输数据时,两端使用对称加密的方式通讯。
PS:以上说明的都是 TLS 1.2 协议的握手状况,在 1.3 协议中,首次创建链接只须要一个 RTT,后面恢复链接不须要 RTT 了。
HTTP 2.0 相比于 HTTP 1.X,能够说是大幅度提升了 web 的性能。
在 HTTP 1.X 中,为了性能考虑,咱们会引入雪碧图、将小图内联、使用多个域名等等的方式。这一切都是由于浏览器限制了同一个域名下的请求数量,当页面中须要请求不少资源的时候,队头阻塞(Head of line blocking)会致使在达到最大请求数量时,剩余的资源须要等待其余资源请求完成后才能发起请求。
你能够经过 该连接 感觉下 HTTP 2.0 比 HTTP 1.X 到底快了多少。
在 HTTP 1.X 中,由于队头阻塞的缘由,你会发现请求是这样的
在 HTTP 2.0 中,由于引入了多路复用,你会发现请求是这样的
HTTP 2.0 中全部增强性能的核心点在于此。在以前的 HTTP 版本中,咱们是经过文本的方式传输数据。在 HTTP 2.0 中引入了新的编码机制,全部传输的数据都会被分割,并采用二进制格式编码。
在 HTTP 2.0 中,有两个很是重要的概念,分别是帧(frame)和流(stream)。
帧表明着最小的数据单位,每一个帧会标识出该帧属于哪一个流,流也就是多个帧组成的数据流。
多路复用,就是在一个 TCP 链接中能够存在多条流。换句话说,也就是能够发送多个请求,对端能够经过帧中的标识知道属于哪一个请求。经过这个技术,能够避免 HTTP 旧版本中的队头阻塞问题,极大的提升传输性能。
在 HTTP 1.X 中,咱们使用文本的形式传输 header,在 header 携带 cookie 的状况下,可能每次都须要重复传输几百到几千的字节。
在 HTTP 2.0 中,使用了 HPACK 压缩格式对传输的 header 进行编码,减小了 header 的大小。并在两端维护了索引表,用于记录出现过的 header ,后面在传输过程当中就能够传输已经记录过的 header 的键名,对端收到数据后就能够经过键名找到对应的值。
在 HTTP 2.0 中,服务端能够在客户端某个请求后,主动推送其余资源。
能够想象如下状况,某些资源客户端是必定会请求的,这时就能够采起服务端 push 的技术,提早给客户端推送必要的资源,这样就能够相对减小一点延迟时间。固然在浏览器兼容的状况下你也可使用 prefetch 。
这是一个谷歌出品的基于 UDP 实现的同为传输层的协议,目标很远大,但愿替代 TCP 协议。
DNS 的做用就是经过域名查询到具体的 IP。
由于 IP 存在数字和英文的组合(IPv6),很不利于人类记忆,因此就出现了域名。你能够把域名当作是某个 IP 的别名,DNS 就是去查询这个别名的真正名称是什么。
在 TCP 握手以前就已经进行了 DNS 查询,这个查询是操做系统本身作的。当你在浏览器中想访问 www.google.com
时,会进行一下操做:
com
这个一级域名的服务器google
这个二级域名www
这个域名配置一个 IP,而后还能够给别的三级域名配置一个 IP以上介绍的是 DNS 迭代查询,还有种是递归查询,区别就是前者是由客户端去作请求,后者是由系统配置的 DNS 服务器作请求,获得结果后将数据返回给客户端。
PS:DNS 是基于 UDP 作的查询。
这是一个很经典的面试题,在这题中能够将本文讲得内容都串联起来。
script
标签的话,会判断是否存在 async
或者 defer
,前者会并行进行下载并执行 JS,后者会先下载文件,而后等待 HTML 解析完成后顺序执行,若是以上都没有,就会阻塞住渲染流程直到 JS 执行完毕。遇到文件下载的会去下载文件,这里若是使用 HTTP 2.0 协议的话会极大的提升多图的下载效率。DOMContentLoaded
事件