yuadhのinterview_note yuadhのinterview_note
前端基础
软件框架
算法|数据结构
基础学科
系统|工具
项目
面试综合
专栏
GitHub (opens new window)
前端基础
软件框架
算法|数据结构
基础学科
系统|工具
项目
面试综合
专栏
GitHub (opens new window)
  • Browser
  • CN
    • 特点
    • URI、URL
    • HTTP首部字段?
    • 请求头
    • 请求首部字段
      • Accept
      • Accept-Charset
      • Accept-Encoding
      • Accept-Language
      • Authorization
      • Host
      • If-Match
      • If-None-Match
      • If-Modified-Since
      • If-Unmodified-Since
      • If-Range
      • Referer——正确Referrer
      • origin
      • User-Agent
    • 响应首部字段
      • Accept-Ranges
      • Age
      • ETag
      • Location
      • Proxy-Authenticate
      • Retry-After
      • Server
      • Vary
      • WWW-Authenticate
    • 通用首部字段
      • Cache-Control(HTTP1.1)
      • Connection
      • Date
      • Transfer-Encoding
      • Upgrade
      • Via
      • Range(用于断点续传
    • 实体首部字段
      • Allow
      • Content-Encoding
      • Content-Language
      • Content-Length
      • Content-Location
      • Content-MD5
      • Content-Rage
      • Content-Type
      • Expires
      • Last-Modified
    • Cookie
      • Set-Cookie
      • Cookie 请求首部字段
    • 请求报文
    • 响应报文
    • 为啥3次握手?
    • 2MSL 等待状态?
    • 为啥4次挥手?
    • SYN攻击?
    • TCP
      • TCP头部很大,具体有哪些报文信息?
    • UDP
    • 应用
    • 数据分片和排序
    • 首部校验
    • 确认和重传(重传机制)
      • 超时重传
      • 快速重传
      • SACK-Selective
      • D-SACK-Duplicate
      • 丢包
      • 网络延时
      • 好处
    • 流量控制
      • 保证次序?
      • 提高吞吐量?
      • 实现最优解?
    • 滑动窗口
      • 正常情况
      • 丢包情况
      • 超时重传
    • 拥塞控制
      • 慢开始
      • 拥塞避免
      • 拥塞发生
      • 快速恢复
    • 流量控制和拥塞控制?
    • 升级 TCP 工作困难
    • TCP 建立连接延迟
    • TCP 存在队头阻塞问题
    • 网络迁移需重新建立 TCP 连接
    • 代理
      • 代理方法
      • 缓存
      • 透明代理
    • 网关
    • 隧道
    • options方法?
    • GET
    • POST
    • 区别
    • GET参数写法固定?
    • POST比GET安全?
    • GET长度限制?
    • POST产生两个TCP数据包?
    • 优点
    • 缺点
    • 一个TCP连接中HTTP请求可一起发送么
    • HTTP1.0
    • HTTP 1.1性能?
    • HTTP1.1相比HTTP1.0
    • 二者存在问题:
    • HTTP1.1性能瓶颈
    • 特点
    • 特点
    • 应用
    • HTTP不断轮询
    • 长轮询
    • Websocket
    • 特性
      • 二进制分帧
      • 首部压缩
      • 多路复用
      • 请求优先级
      • 流量控制
      • 服务端推送
      • 数据流
    • 缺陷
    • 特性
      • 连接迁移
      • 无队头阻塞
      • 自定义拥塞控制
      • 前向安全和前向纠错
    • 为什么HTTP3.0使用UDP?
    • SSL/TLS
      • 作用
      • SSL/TLS的四次握手
    • 🍪HTTPS保证传输安全?
      • TLS1.0
      • TLS.12
    • 🔥 HTTPS、HTTP
    • HTTP存在风险
      • HTTPS 在 HTTP 与 TCP 层间加入SSL/TLS 协议,解决上述风险
    • HTTPS 如何解决上面三个风险?
    • 混合加密
    • 摘要算法
    • 数字签名
    • 数字证书
    • 域名
    • 分布式
    • 本地DNS服务器
    • 递归、迭代查询
    • 所有 DNS 查询都必须遵循递归 + 迭代 ?
    • DNS 优化和应用
      • DNS缓存
      • 负载均衡
      • CDN(Content Delivery Network)
      • dns-prefetch
    • 为啥使用UDP?
    • 解析不存在的域名?
    • TCP/IP协议族?
    • TCP 协议保证页面文件完整送达浏览器?
    • ✔️ QUIC协议
    • 特点
      • 无队头阻塞
      • 流量控制
      • 更快的连接建立
      • 连接迁移
    • 优点
  • CSS
  • Git
  • HTML
  • JS
  • Optimize
  • OS
  • Project-Others
  • React
  • Review
  • Vue
  • 场景题
  • 备注
  • 专栏
yuadh
2022-12-19
目录

CN

# OSI七层模型

OSI将计算机网络体系结构分为7层

  1. 物理层,通信信道上的原始比特流传输(比特流)

  2. 数据链路层(定义数据的基本格式)(帧)

  3. 网络层。主要协议是IP和ARP(定义ip编址,定义路由功能,如不同设备间的数据转发)(包)

  4. 传输层,为两台主机进程间通信提供服务,主要协议为TCP,UDP(数据段)

  5. 会话层,管理不同用户和进程之间的对话

  6. 表示层,处理两个通信系统中交换信息的表示方式

  7. 应用层,定义应用进程间交互规则,为不同的网络应用提供服务。域名系统 DNS,支持万维网应用的 HTTP 协议,电子邮件系统采用的 SMTP协议(报文)

简单网络管理协议(SNMP (opens new window)) 是一种应用层协议

DHCP(动态主机配置协议 (opens new window))是一个局域网的网络协议

查看源图像

应用层发送http请求,到传输层通过三次握手建立tcp/ip连接,到网络层的ip寻址,再到数据链路层封装成帧,最后到物理层利用物理介质传输

# 💚 HTTP协议?

超文本传输协议,HyperText Transfer Protocol

  • 超文本
  • 传输
  • 协议
图片

协议特点:

  • 「协」,代表必须有两个以上的参与者。例如三方协议里的参与者有三个:你、公司、学校三个;租房协议里的参与者有两个:你和房东
  • 「议」,代表对参与者的行为约定和规范。例如三方协议里规定试用期期限、毁约金等;租房协议里规定租期期限、每月租金金额、违约如何处理等

HTTP是一个计算机世界的协议,确立了一种计算机之间交流通信的规范,以及相关的各种控制和错误处理方式

HTTP是一个双向协议!

超文本:HTTP传输的内容

在HTTP眼中,简单字符文字,图片,视频,压缩包等都算作 文本。超文本——超越了普通文本的文本,有超链接。HTML就是最常见的超文本

HTTP是一个在计算机世界里专门在 两点 之间 传输 文字、图片、音频、视频 等 超文本 数据的 约定和规范

那HTTP是用于从互联网传输超文本到本地浏览器的协议,对吗?

不对,因为也可以是服务器<-->服务器,所以采用两点间的描述更准确

# 特点

支持客户/服务器模式

简单快速:客户端请求服务时,只需要传送请求方法和路径。HTTP协议简单,HTTP服务器的程序规模小,通信速度快

灵活:允许传输任意类型数据对象。正在传输的类型由Content-type标记

无状态:HTTP协议无法根据之前的状态处理本次请求

无连接:每次连接只能处理一个请求。服务器处理完请求,收到应答后即断开连接,节省时间

# URI、URL

1651277727760
  • URN或同时具备locators 和names特性
  • URN像一个人的名字,URL像这个人的地址
  • 换句话说:URN确定东西的身份,URL提供找到它的方式

URL是URI的一种,不是所有的URI都是URL;URI唯一标识身份,URL给出访问机制(http/ftp/telnet等)

# HTTP首部字段?

Accept: 允许的媒体类型
Connection: 连接选项,例如是否允许代理
Host: 客户端发送请求时,指定服务器的域名
If-None-Match: 判断请求实体的Etag是否包含在If-None-Match中,如果包含,则返回304,使用缓存
If-Modified-Since: 判断修改时间是否一致,如果一致,使用缓存
If-Match: 与If-None-Match相反
If-Unmodified-Since: 与If-Modified-Since相反
Referer: 这个请求发起的源头
Cache-Control: 缓存策略,如max-age:100
Connection: 连接选项,例如是否允许代理
Content-Encoding: 返回内容的编码,如gzip
Etag: entity tag,实体标签,给每个实体生成一个单独的值,用于客户端缓存,与If-None-Match配合使用
Expires: 设置缓存过期时间,Cache-Control也会相应变化
Last-Modified: 最近修改时间,用于客户端缓存,与If-Modified-Since配合使用
Pragma: 似乎和Cache-Control差不多,用于旧的浏览器
Server: 服务器信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 🌈 状态码

image-20220531165001489

1xx Informational 提示信息,请求正在处理 2xx Success(成功)请求正常处理完毕

  • 200 请求成功
  • 201 请求成功且服务器创建了新的资源
  • 202 已接受,但未处理完成
  • 203 (非授权信息) 已成功处理,但返回信息可能来自另一个源
  • 204 成功处理,但没有返回内容
  • 205 重置内容 服务器成功执行请求,没有返回内容,与204不同,他需要请求者重置文档视图(比如,清除表单内容,重新输入)
  • **206 部分内容 服务器成功执行部分请求 ,**应用于 HTTP 分块下载或断点续传,响应返回的 body 数据并不是资源的全部,也是处理成功的状态

3xx Redirection(重定向)资源位置变动

  • 300(多种选择)
  • 301 (Permanently Moved) 永久性重定向,请求的资源已不存在,需用新的 URL 访问

永久:域名、服务器、网站架构大幅度改变,如启用新域名、服务器切换到新机房、网站目录层次重构

  • 302 (**Temporarily Moved **) 临时重定向,请求的资源还在,暂时需要用另一个 URL 来访问

场景:系统维护,告诉用户一会儿再来。服务降级,双十一,将不重要的功能入口先关闭,保证核心服务正常运行

301 和 302 都会在响应头里使用字段 Location,指明后续要跳转的 URL,浏览器自动重定向新的 URL

  • 303 请求对应的资源存在另一个URL,使用GET获取资源

  • 304 ——缓存重定向, 不具有跳转含义,可继续使用缓存资源。 服务器只根据请求头中的 If-None-Match 和 响应头中的 ETag 比较判断是否返回 304,一致返回 304

  • 305 (使用代理)

  • 307 (临时重定向)类似于302, 但重定向后请求里的方法和实体不允许变动,含义比302明确

4xx Client error(客户端错误)

  • 400 不理解请求的语法(一般为参数错误)
  • 401 未授权
  • 403 禁止访问资源,可能是客户端权限不对
  • 404 资源不存在(错误 URL)或找不到请求的网页,拒绝请求且不想说明理由
  • 405(方法禁用)
  • 406(不接受)
  • 407(需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理
  • 408(请求超时)

5xx Server Error 服务器处理请求出错

  • 500 Internal Serve Error, 与 400 类型,笼统通用
  • 501 客户端请求的功能还不支持,类似“即将开业,敬请期待”
  • 502 Bad Gateway 通常是服务器作为网关或代理时返回,服务器自身工作正常,访问后端服务器发生错误
  • 503 Service Unavailable,类似“网络服务正忙,请稍后重试”
  • 504 gateway time-out,服务器在尝试加载网页或填写浏览器的另一个请求时未从其访问的另一台服务器收到响应

502和504 区别?

都和网关有关

502 一般表现为我们自己写的 应用层服务 挂了,或者网关指定的上游 服务直接指错了地址,网关层无法接收响应

504 一般是 应用层服务 超时,超过了 网关配置的时间,如查库操作耗时十分钟,超过了nginx配置的超时时间

# HTTP报文

分为

请求报文(请求行 请求头部 空行 请求体)

响应报文(状态码 消息报头 响应正文)

服务端收到请求后只返回响应头,不会发送相应内容

请求和响应报文唯一区别:第一行用状态信息代替了请求信息

# 请求头

HTTP报文一共有四种首部字段(请求头):请求首部字段、响应首部字段、通用首部字段、实体首部字段

# 请求首部字段

# Accept

Accept: text/html 浏览器可以接受服务器回发的类型

Accept: / 浏览器可以处理所有类型,(一般浏览器发给服务器都是发这个)

# Accept-Charset

通知服务器用户代理(浏览器)支持的字符集及字符集的相对优先顺序

Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
1

中的unicode-1-1;q=0.8是一个整体,表示unicode编码优先级为0.8,小于默认的iso编码优先级(默认q=1);不要以为分号(;)为分割符,其实逗号(,)才是分割符

# Accept-Encoding

用户代理支持的内容编码及内容编码的优先级顺序。 可一次性指定多种内容编码

常见的编码方式有:gzip、compress、deflate、identity

# Accept-Language

告知服务器浏览器能够接收的语言 ,及相对优先级

# Authorization

Web认证信息

# Host

客户端发送请求时,指定服务器的域名

Host:www.1024nav.com (opens new window) 请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。虚拟主机位于同一个IP上,使用首部字段 Host 区分

若服务器未设定主机名,Host为空值

有了 Host ,可以将请求发往「同一台」服务器上的不同网站

1649940518657

# If-Match

当If-Match的字段值跟Etag值匹配时,服务器才会接收请求

# If-None-Match

If-None-Match 的字段值与 ETag值不一致时, 可处理该请求。 与 If-Match 首部字段的作用相反

# If-Modified-Since

比较资源更新时间

# If-Unmodified-Since

# If-Range

附带条件之一。 告知服务器若指定的 If-Range 字段值(ETag 值或者时间) 和请求资源的 ETag 值或时间一致时, 则作为范围请求处理。 反之, 则返回全体资源

我们思考一下不使用首部字段If-Range 发送请求的情况。 服务器端的资源如果更新, 那客户端持有资源中的一部分也会随之无效,当然,范围请求作为前提是无效的。这时,服务器会暂且以状态码 412:Precondition Failed作为响应返回, 其目的是催促客户端再次发送请求。这样一来,与使用首部字段 If-Range比起来,就需要花费两倍的功夫
1

形如If--xxx这种样式的请求首部字段,可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求

# Referer——正确Referrer

Referer: https://www.1024nav.com (opens new window) 当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的

告知服务器 该页面的来源URL,精确到详细页面地址

# origin

最初的请求从哪里发起(精确到端口),比referer更注重隐私

# User-Agent

User-Agent: user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36,告诉HTTP服务器,客户端使用操作系统和浏览器的名称和版本

# 响应首部字段

# Accept-Ranges

是否接受字节范围请求

# Age

告知客户端,源服务器在多久前创建了响应,单位为秒

# ETag

告知客户端实体标识。一种将资源以字符串形式做唯一标识的方式。服务器为每份资源分配对应的 ETag值 资源更新时,ETag 更新。生成 ETag 时,没有统一的算法规则,仅由服务器分配

# Location

将响应接收方引导至某个与请求 URI 位置不同的资源

该字段配合 3xx : Redirection 的响应, 提供重定向的URI

浏览器收到301/302报文,检查响应头中是否有location。若有,则提取出URI并发出新的请求,相当于 自动点击这个链接

# Proxy-Authenticate

代理服务器对客户端的认证信息

# Retry-After

对再次发起请求的时机要求

# Server

HTTP服务器的安装信息

# Vary

代理服务器缓存的管理信息

CORS 和缓存 如果服务器未使用“*”,而是指定了一个域,为了向客户端表明服务器的返回会根据Origin请求头而有所不同,必须在Vary响应头中包含Origin

Access-Control-Allow-Origin: https://developer.mozilla.org
Vary: Origin
1
2

# WWW-Authenticate

认证信息

# 通用首部字段

# Cache-Control(HTTP1.1)

private :默认, 只能作为私有缓存,不能用户间共享

public 响应会被缓存,向任意方提供响应的缓存

must-revalidate 可缓存但必须再向源服务器进行确认

:no-cache 缓存前必须确认其有效性, 该指令还是会使用缓存,只不过使用前要确认其新鲜程度(协商缓存)

: max-age=31536000 设置缓存最大的有效时间,单位是秒

:no-store 真正的所有内容都不缓存

# Connection

客户端要求服务器使用 TCP 持久连接,以便其他请求复用

HTTP 对 TCP 连接的使用,分为两种方式:“短连接”和“长连接”(“长连接”又称“持久连接”,洋文叫做“Keep-Alive”或“Persistent Connection”,一个 TCP 连接从头用到尾)

两个作用:

  • 控制不再转发给代理的首部字段
  • 管理持久连接

Connection: keep-alive 一个网页打开后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,继续使用这一条已经建立的连接

Connection: close 代表一个Request完成后,客户端和服务器之间用于传输HTTP数据的TCP连接会关闭, 当客户端再次发送Request,需要重新建立连接

# Date

# Transfer-Encoding

# Upgrade

# Via

追踪客户端与服务器之间的请求和响应报文的传输路径。(各个代理服务器会往Via首部添加自身服务器的信息)

# Range(用于断点续传

Range:bytes=0-5 指定第一个字节的位置和最后一个字节的位置。告诉服务器自己想取对象的哪部分

# 实体首部字段

是包含在请求报文和响应报文中的实体部分所使用的首部,用于补充内容的更新时间等与实体相关的信息

# Allow

# Content-Encoding

说明数据的压缩方法。表示服务器返回的数据使用了什么压缩格式

图片

# Content-Language

# Content-Length

本次回应的数据长度

# Content-Location

# Content-MD5

# Content-Rage

# Content-Type

告诉客户端,本次媒体资源格式,请求头则代表请求体资源类型;响应头则代表响应体资源类型

Content-Type: text/html; charset=UTF-8;
Content-Type: multipart/form-data;
1
2

图片

# Expires

将资源失效的日期告知客户端。缓存服务器(代理服务器)在接收到含有首部字段 Expires的响应后,以缓存来应答请求,在Expires 字段值指定的时间之前,响应的副本会一直被保存。当超过指定的时间后,缓存服务器在请求发送过来时,会转向源服务器请求资源

源服务器不希望缓存服务器对资源缓存时, 最好在 Expires 字段内写入与首部字段 Date 相同的时间值

但是,当首部字段Cache-Control 有指定 max-age 指令时,比起首部字段 Expires,会优先处理 max-age指令

# Last-Modified

指明资源最终修改的时间。 与请求头If-Modified-Since是一对

# Cookie

可校验 Cookie 的有效期,及发送方的域、路径、协议等信息,所以正规发布的 Cookie 内的数据不会因来自其他Web 站点和攻击者的攻击而泄露

# Set-Cookie

当服务器准备开始管理客户端的状态时,会事先告知各种信息。

Set-Cookie: status=enable; expires=Tue, 05 Jul 2011 07:26:31 GMT; path
1

cookie字段

属性 作用
name=value 赋值cookie的名称和值
expires=date cookie有效期
path=path 限制指定的Cookie的发送范围的文件目录,默认为当前
domain=domain 限制cookie生效的域名,默认为创建cookie的服务域名
HttpOnly 不能通过 JS 访问 Cookie,减少 XSS 攻击
secure 只能在协议为 HTTPS 的请求中携带
SameSite 浏览器不能在跨域请求中携带 Cookie,减少 CSRF 攻击
  • expires

指定 Cookie 有效期。省略 expires 属性时,其有效期仅限于维持浏览器会话(Session)时间段内

  • domain

cookie作用域

比如,指定 .example.com 后,除 .example.com 以外, www.example.com或 www2.example.com等子域名都可以访问Cookie

  • secure

限制 Web 页面仅在 HTTPS 安全连接时,才可以发送 Cookie

Set-Cookie: name=value; secure
1

以上例子仅当在https://www.example.com/(HTTPS)安全连接的情况下才会进行Cookie 的回收

当省略 secure 属性时,不论 HTTP还是 HTTPS,都会对 Cookie 进行回收

  • HttpOnly

禁止JS脚本访问 Cookie

Set-Cookie: name=value; HttpOnly
1
  • SameSite

是否允许跨域时携带Cookie

strict:任何情况都不允许作为第三方cookie

Lax:宽松模式,只能在请求方法为Get且请求改变了当前页面或打开新的页面时,允许cookie跨域访问

None:默认模式,请求自动携带cookie

# Cookie 请求首部字段

告知服务器,当客户端想获得 HTTP状态管理支持时, 会在请求中包含从服务器接收到的 Cookie。 接收到多个Cookie 时,同样可以以多个 Cookie形式发送。

Cookie: status=enable
1

# 请求报文

请求头header细分为

  • 请求行

  • 请求头

header包括

  1. 请求方法
  2. 协议
  3. 目标url

请求体body,包括请求的内容

1651278369602

# 响应报文

响应行

响应头

响应体

1651278395720

# ✔️ 三次握手

  1. 建立连接。服务端 初始化创建连接,确认接收后的状态为SYN_receive。客户端等待状态为SYN_send
  2. 收到了客户端的SYN,此时服务器处于SYN_RECD状态
  3. 客户端收到服务端的SYN/ACK数据包后,发送标有ACK的数据包。ack=y+1,seq=x+1,作为应答。客户端和服务器端状态变化为established

ack(Acknowledge Number 确认序列号)——32位,确认接收对方的数据,ACK 为 1 时该确认序列号字段才有效——解决不丢包的问题

seq(Sequence Number 序列号)——32位,标识发送数据,连接请求报文段,客户端进入SYN_SENT,等待服务器确认,发送自己的数据,确保数据通信有序性

SYN(synchronous)——同步序列号,发起一个新连接**(带有SYN的过程包不带数据),第三次握手可携带数据),消耗一个序号**。SYN 标志位和 ACK 标志位搭配使用,当连接请求时,SYN=1,ACK=0连接被响应时,SYN=1,ACK=1

ACK(acknowledgement)——标志位,应答确认序号有效,我接收到的信息确实是你所发送的信息。发送方到接收方通道没问题

SYN+ACK(验证接收方到发送方通道)——双方通信无误必须是两者互相发送消息都无误

img

# 为啥3次握手?

本质是,信道不可靠,但是通信双方需要就某个问题达成一致。三次通信是理论上最小值,3次握手不是TCP本身的要求,而是为了满足“在不可靠信道上可靠传输信息”这一需求导致的。为了判断双方的接收和发送能力是否正常

红蓝军 问题,由于信息可能丢失,为了保证信息传达准确性,我们需多次传递,通信次数越多,信息到达概率越大。TCP 采用三次握手,尽可能可靠

防止已失效的连接请求报文段突然又传送到了服务端,产生错误

在谢希仁著《计算机网络》书中同时举了一个例子,如下:

“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。

本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。

假设不采用“三次握手”,只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。

但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”

握手次数不过是提高“它是可用的”这个结论的可信度

四次握手没必要

# ✅ 四次挥手

【四次挥手是2+2】留下扫尾工作的时间

客户端和服务端均能主动关闭连接

FIN=1 ACK=1 表示TCP连接释放报文段
1
image-20220610203253228
  1. TCP是全双工模式,当主机1发出FIN连接释放报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;并停止再发送数据,主动关闭TCP连接。进入FIN_WAIT1(终止等待状态1),等待服务器确认

但这个时候主机1还是可接受来自主机2的数据

  1. 当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1;**服务器:我请求报文接收完了,准备关闭,你也准备吧。**此时服务端处于CLSE_WAIT状态,即服务端收到连接释放报文段后即发出确认报文段。此时的TCP处于半关闭状态

  2. 当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,**我也没有数据要发送了,**之后彼此就会愉快的中断这次TCP连接。服务端发送连接释放报文段,进入LAST_ACK状态,等待客户端确认

  3. 客户端向服务器发送报文段,ACK+seq+ack,进入等待TIME_WAIT状态。需要过一阵子以确保服务端收到自己的ACK报文段后才进入CLSED状态,服务器收到报文段后关闭连接,发起方等待一段时间后没有回复,正常关闭。浏览器:我响应报文接收完,准备关闭了,你也准备关闭吧

如果要正确的理解四次分手的原理,就需要了解四次分手过程中的状态变化

  • FIN_WAIT_1: FIN_WAIT_1和FIN_WAIT_2状态表示等待对方的FIN报文

区别是:FIN_WAIT_1状态是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态(等待对方的ACK报文)

而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,在实际正常情况下,无论对方何种情况,都应马上回应ACK报文,所以FIN_WAIT_1状态一般比较难见到,而FIN_WAIT_2状态常常可以用netstat看到(主动方——A)

  • FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你(ACK信息),稍后再关闭连接(主动方)
  • CLOSE_WAIT:表示在等待关闭

怎么理解呢?

当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有,那么你也可以 close这个SOCKET,发送FIN报文给对方,即关闭连接。所以在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接(被动方)

  • LAST_ACK: 是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,即可以进入到CLOSED可用状态(被动方)
  • TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态**,而无须经过FIN_WAIT_2状态(主动方)**
  • CLOSED: 连接中断

# 2MSL 等待状态?

TIME_WAIT状态也为2MSL等待状态。报文段最大生存时间 MSL(Maximum Segment Lifetime)

  1. 保证客户端发送的最后一个ACK报文段能够到达server
  2. 防止“已失效的连接请求报文段”出现在本连接中

客户端发送完最后一个ACK报文段后,再经过 2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段

client端接到第三次挥手的时候,client端不会马上CLOSED,而是等待两个msl再关闭

因为如果client端发送的第四次挥手server端没收到,server可能会重传第三次挥手的包,并且依旧在TIME_WAIT状态

这时 如果client直接关闭请求,会导致server端一直重传;有了2MSL之后(也就是等一个来回),就可以接收到server端重传的挥手报文,重新进行第四次挥手

为什么是两个msl,一个不可以吗

因为server端检测到丢包就需要一个msl,还没等server端重传,client端就CLOSED了

# 为啥4次挥手?

当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。ACK 用来 应答,SYN 用来 同步

关闭连接时,服务器收到对方的FIN报文时,仅表示对方不再发送数据了,但还能接收数据,而自己也未必不发送数据了,所以服务器可立即关闭,也可发送数据,再发送FIN报文表示同意关闭连接,因此,服务器ACK和FIN一般分开发送

# SYN攻击?

服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器 容易受到SYN洪泛攻击

SYN攻击:Client在短时间内伪造大量不存在的IP地址,并向Server不断地发 送SYN包,Server回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,引起网络拥塞甚至系统瘫痪

常见的防御 SYN 攻击的方法

  1. 缩短超时(SYN Timeout)时间
  2. 增加最大半连接数
  3. 过滤网关防护
  4. SYN cookies技术

# 啥时候用TCP/UDP?

实时性要求比较高,选择udp,比如游戏,媒体通信和实时视频流,即出现传输错误也可以容忍

其他大部分情况,都是用TCP,因为要求传输内容可靠,不出现丢失

# ⚠️TCP、UDP?

TCP:Transmission Control Protocol, 传输控制协议

UDP :User Datagram Protocol 用户数据报协议

image-20220830184928387

# TCP

  1. 面向连接
  2. 可靠交付
  3. 无差错,不丢失,无重复,按序到达
  4. 面向字节流
  5. 首部20字节,开销大
  6. 只能点对点全双工可靠信道

img

# TCP头部很大,具体有哪些报文信息?

# UDP

  1. 无连接(利用IP提供面向无连接通信服务)
  2. 尽最大努力交付,不可靠(传输途中出现丢包,不负责重发;当包的到达顺序乱序,不纠正)
  3. 面向报文
  4. 无拥塞控制(按照应用程序发来的数据原样发送,即使出现网络拥堵,也不会进行流量控制等避免拥塞的行为)
  5. 支持一对一,一对多,多对一和多对多的交互通信
  6. 首部开销小,8字节
  7. 实时性好,效率高
  8. 不可靠信道
  9. 无论应用层交给UDP多长的报文,统统发送,一次发送一个报文

简言之:

  • TCP向上层提供面向连接的可靠服务,建立连接3次握手、断开连接4次挥手;UDP向上层提供无连接不可靠服务,发送端只负责将数据发送到网络,接收端从消息队列读取
  • UDP没有TCP传输来的准确,但是在很多实时性要求高的地方有所作为
  • 对数据准确性要求高,速度可以相对较慢,可选用TCP
  • TCP面向字节流,将应用层报文看成一串无结构的字节流,分解为多个TCP报文段传输,在目的站重新装配。UDP面向报文,不会拆分应用层报文,只保留报文边界,一次发送一个报文,接收方去除报文首部后,原封不动将报文上传上层应用

# 应用

image-20220610154248086

# 🌰 TCP为什么可靠?

可靠:保证接收方进程从缓存区读出的字节流和发送方发出的字节流完全一样

实现可靠传输的机制有 校验、序号、确认和重传

# 数据分片和排序

tcp会按 最大传输单元(MTU)合理分片,接收方缓存未按序到达的数据, 重新排序后交给应用层

UDP:IP数据报大于1500字节,大于MTU。这时发送方的IP层需要分片,把数据报分成若干片,每一片都小于MTU

而接收方IP层则需要重组 数据报

由于UDP的特性,某一片数据丢失时,接收方无法重组数据报,导致丢弃整个UDP数据报

# 首部校验

接收端用CRC检验整个报文段有无损坏

增加伪首部,反码求和

TCP协议规定,TCP的首部字段中有一个字段是校验和,发送方将伪首部、TCP首部、TCP数据使用 累加和校验 方式计算出一个数字,存放在首部的校验和字段里,接收者收到TCP包后重复这个过程,将计算出的校验和 和接收到的首部中的 校验和比较,如果不一致则 说明数据在传输过程中出错。

但这个机制能够保证检查出一切错误吗?显然不能。

因为这种校验方式是累加和,将一系列的数字(TCP协议规定的是数据中的每16个比特位数据作为一个数字)求和后取末位。 但是小学生都知道A+B=B+A,假如在传输的过程中有前后两个16比特位的数据前后颠倒了(至于为什么这么巧合?我不知道,也许路由器有bug?也许是宇宙中的高能粒子击中了电缆?反正这个事情的概率不为零,就有可能会发生),导致 校验和的计算结果和颠倒之前一样,接收端肯定无法检查出这是错误的数据

解决方案

传输之前先使用MD5加密数据获得摘要,跟数据一起发送到服务端,服务端接收之后对数据进行MD5加密,如果加密结果和摘要一致,则认为没有问题

# 确认和重传(重传机制)

TCP面向字节流,一个字节一个序号

ACK信号,发送方按照顺序给要发送的数据包的每个字节都标上号

TCP实现可靠传输的方式之一,通过 序列号和确认应答 实现

基于序号机制,接收方接收到某个报文段后,发送给发送方一个确认号,采用累计确认法,表示已收到消息

保证因链路故障未能到达数据能被 多次重发

image-20220610154432931

不一定能如上图那么顺利进行正常的数据传输,万一在传输过程中丢失了呢?

TCP针对数据包丢失的情况——重传机制

常见的重传机制

  • 超时重传
  • 快速重传
  • SACK
  • D-SACK

# 超时重传

发送数据时,设定一个定时器,当超过指定的时间后,没有收到对方的 ACK 确认应答报文,重发该数据

两种情况发生超时重传:

  1. 数据包 丢失
  2. 确认应答丢失
image-20220610154505391

超时时间该设置为多少?

RTT(Round-Trip Time 往返时延):数据发送时刻到接收到确认的时刻的差值

RTO (Retransmission Timeout超时重传时间)

image-20220610154536429

假设在重传的情况下,超时时间 RTO 「较长或较短」时,发生什么事情?

image-20220610154600923
  1. 超时时间 RTO 较大,重发就慢,丢了老半天才重发,没有效率,性能差

  2. 超时时间 RTO 较小时,导致可能没有丢就重发,于是重发就快,增加网络拥塞,导致更多的超时,更多的超时导致更多的重发

超时重传时间RTO的值应该略大于报文往返RTT的值。且RTO动态变化

image-20220610154629339

超时触发重传存在的问题,超时周期可能相对较长,可以以更快捷的方式操作吗?——快速重传

# 快速重传

发送方收到冗余确认,判断报文段丢失

不以时间为驱动,以数据驱动重传

image-20220610154652815

上图,发送方发出了 1,2,3,4,5 份数据:

  • Seq1先到了,于是ACk回2

  • 结果2没有到,3到了,所以ACK还是回2

  • 后面的4和5都到了,但是ACK还是回2,因为2号包没收到

  • 发送端收到了3个ACK=2的确认,知道2没有收到,在定时器过期前,重传丢失的2

  • 最后,接收到了2,因为此时3 4 5包都收到了,所以ACK回6

快速重传的工作方式就是当收到3个相同的ACK报文时,在定时器过期之前,重传丢失的报文段

面临的问题:重传的时候,是重传之前的一个,还是重传所有?

对以上的例子,重传2?还是重传2 3 4 5 呢?因为发送端并不清楚这三个连续的ACK 2是谁传回来的

所以,有了SACK方法——解决不知道该重传哪些TCP报文

# SACK-Selective

( Selective Acknowledgment 选择性确认)

这种方式需要在 TCP 头部「选项」字段里加一个 SACK ,它可以将缓存的地图发送给发送方,这样发送方就知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据

下图,发送方收到了三次同样的 ACK 确认报文,于是触发快速重发机制,通过 SACK 信息发现只有 200~299 这段数据丢失,重发时,就只选择这个 TCP 段重复发送

image-20220610154733745

如果要主持SACK,必须双方都要支持

# D-SACK-Duplicate

Duplicate SACK 又称 D-SACK,其使用了 SACK 告诉「发送方」有哪些数据被重复接收了

# 丢包

image-20220610154753403
  • 「接收方」发给「发送方」的两个 ACK 确认应答都丢失了,所以发送方超时后,重传第一个数据包(3000 ~ 3499)

  • 「接收方」发现数据重复收到,于是回了一个 SACK = 3000~3500,告诉「发送方」 3000~3500 的数据早已被接收,因为 ACK 都到了 4000 了,意味着 4000 之前的所有数据都已收到,所以这个 SACK 就代表着 D-SACK

  • 这样「发送方」就知道了,数据没有丢,是「接收方」的 ACK 确认报文丢了

# 网络延时

image-20220610154819903
  • 数据包(1000~1499) 被网络延迟了,导致「发送方」没有收到 Ack 1500 的确认报文
  • 后面报文到达的三个相同的 ACK 确认报文,触发了快速重传机制,但是在重传后,被延迟的数据包(1000~1499)又到了「接收方」
  • 所以「接收方」回了一个 SACK=1000~1500,因为 ACK 已经到了 3000,所以这个 SACK 是 D-SACK,表示收到了重复的包
  • 这样发送方就知道快速重传触发的原因不是发出去的包丢了,也不是因为回应的 ACK 包丢了,而是因为网络延迟

# 好处

  1. 让「发送方」知道,是发出去的包丢了,还是接收方回应的 ACK 包丢了
  2. 知道是不是「发送方」的数据包被网络延迟了
  3. 知道网络中是不是把「发送方」的数据包给复制了

# 流量控制

发送方不能无脑发送数据给接收方,需要考虑接收方处理能力

如果一直发数据给对方,处理不过来会触发重发机制,浪费网络流量

流量控制——为了控制发送方发送速率,保证接收方来得及接收

TCP 提供一种机制可让「发送方」根据「接收方」的实际接收能力控制发送的数据量——流量控制

# 保证次序?

“停止等待”

1649667764267

发送方发送一个包1,这时候接收方确认包1。发送包2,确认包2。

这样一直下去,直到完全发送完所有数据,结束。就解决了丢包,出错,乱序等一些情况!

同时也存在问题。问题:吞吐量非常低。我们发完包1,一定要等确认包1.我们才能发送第二个包

# 提高吞吐量?

两个包一起发送,一起确认。可以看出我们改进的方案比之前的好很多,所花的时间只是一个来回的时间

# 实现最优解?

每次需要发多少个包过去呢?发多少是最合适?

我们可不可以把第一个包和第二个包发过去后,收到第一个确认包就把第三个包发过去呢? 而不是去等到第二个包的确认包才去发第三个包——"滑动窗口"的实现

为每个数据包确认应答的缺点:包往返时间越长,网络吞吐量越低

# 滑动窗口

你一句我一句,效率低。如果你说完一句话,我没有及时回复,你不是要干等着我做完其他事,我回复你,你才能说下一句话,显然不现实

image-20220610154843457

因此,这种传输方式的缺点——数据包的往返时间越长,通信效率越低

为解决这个问题,TCP引入了窗口这个概念,即使往返时间较长,也不会降低网络通信效率

窗口大小:无需等待确认应答,可以继续发送数据的最大值

实际上是OS开辟的一个缓存空间,发送方在等到确认应答返回前,必须在缓冲区保留已发送的数据。若按期收到确认应答,此时数据可以从缓存区中清除

假设窗口大小为 3 个 TCP 段,那么发送方就可以「连续发送」 3 个 TCP 段,中途若有 ACK 丢失,可以通过「下一个确认应答进行确认」。下图:

image-20220610154906741

只要发送方收到了ACK700的确认应答,意味着700之前的所有数据接收方都收到了——累计确认(累计应答)

窗口大小谁决定?

TCP 头里有一个字段 Window,就是窗口大小

这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端根据这个接收端的处理能力发送数据,而不会导致接收端处理不过来

因此,通常窗口大小由接收方的窗口大小决定

发送方发送的数据不能超过接收方窗口大小,否则接收方无法正常接收数据

发送方的滑动窗口

我们先来看看发送方的窗口,下图就是发送方缓存的数据,根据处理的情况分成四个部分,其中深蓝色方框是发送窗口,紫色方框是可用窗口:

image-20220610154926444

在下图,当发送方把数据「全部」都一下发送出去后,可用窗口的大小为 0 ,表明可用窗口耗尽,没收到 ACK 确认之前无法继续发送数据

image-20220610154946821

在下图,当收到之前发送的数据 32~36 字节的 ACK 确认应答后,如果发送窗口的大小没有变化,则滑动窗口往右边移动 5 个字节,因为有 5 个字节的数据被应答确认,接下来 52~56 字节又变成了可用窗口,那么后续也就可以发送 52~56 这 5 个字节的数据了

image-20220610155007468

接收方的滑动窗口

接下来我们看看接收方的窗口,接收窗口相对简单一些,根据处理的情况划分成三个部分:

image-20220610155024713

接收窗口和发送窗口的大小是相等的吗?

并不完全相等,接收窗口大小约等于发送窗口的大小

因为滑动窗口不是一成不变。比如,当接收方的应用进程读取数据的速度非常快的话,这样接收窗口可以很快空缺出来。那么新的接收窗口大小,是通过 TCP 报文中的 Windows 字段来告诉发送方。这个传输过程存在时延,所以接收窗口和发送窗口是约等于的关系

1649667798090

# 正常情况

1649667804685

4号包已经被对方接收到,窗口往右移一格。我们把11号包读进缓存。进入“待发送”的状态。接下来的操作就是一样的了,确认包后,窗口继续往后移,将未发送的包读进缓存,把“待发送”的包状态变为“已发送”

# 丢包情况

可能我们包发过去,但是对方的ACK丢了

也有可能是我们的包并没有发过去

站在发送方的角度看就是我们并没有收到ACK

1649667812129

因此,我们会一直等待ACK,若一直等不到,我们也会把读进缓存的待发送的包也一起发过去。但是,这时我们的窗口已经满了,就不能把12号包读进来,而是始终在等待5号包的ACK

若我们这ACK始终不来,咋办?

# 超时重传

ACK需要按顺序来,必须等到5的ACK收到了,才会把6-11的ACK发送过去。酱紫也保证了滑动窗口的顺序

1649667818756

此时,5号包已经接收到了ACK,后面的6-8号包也已经发送过去已ACK。窗口继续向后移动

1649667826751

rwnd表示receiver window

该协议允许发送方在停止并等待确认前发送多个数据分组。发送方不必每发一个分组就停下来等待确认。因此该协议可以加速数据的传输,提高网络吞吐量

滑动窗口大小——接收方还有多大的缓冲区可以用于接收数据,用以 解决发送速率过快导致接收方不能接收 的问题。发送方 通过滑动窗口大小确定应该发送多少字节数据。当滑动窗口为 0 时,发送方一般不再发送数据报,两种情况除外,一种情况是可以发送紧急数据

发送方A的发送窗口表示:在没有收到B确认的情况下,A可以连续把窗口内的数据都发送出去,凡是已经发送过的数据,在未收到确认之前都必须暂时保留,以便在超时重传时使用

发送窗口的位置由窗口前沿和后沿位置共同确定:

  • 后沿不动——没有收到新的确认
  • 后沿前移——收到了新的确认
  • 前沿前移——收到新的确认,或者接收方的窗口变大
  • 前沿不动——没有收到新的确认,接收方的窗口大小不变,或者收到了新的确认,但接收方的窗口变小
  1. 发送端只能发送接收端指定的报文大小,超过了则暂停发送信息

  2. 滑动窗口由窗口值控制传输流量的大小;利用重发机制解决发送端消息丢失;利用 持续计数器和探测报文解决接收端发送的窗口值丢失导致的无限等待情况

# 拥塞控制

流量控制是避免「发送方」的数据填满「接收方」的缓存,但是并不知道网络中发生了什么

一般来说,计算机网络都处在一个共享的环境。因此也有可能会因为其他主机之间的通信使得网络拥堵

网络拥堵时,如果继续发送大量数据包,可能会导致数据包时延、丢失等,这时 TCP 会重传数据,但是一重传就会导致网络的负担更重,导致更大的延迟以及更多的丢包,这个情况就会进入恶性循环被不断地放大....

拥塞控制,避免「发送方」的数据填满整个网络

为了在「发送方」调节所要发送数据的量,定义一个叫做「拥塞窗口」的概念

RTT:数据从发送到接收到对方响应之间的时间间隔,即数据报在网络中一个往返用时。大小不稳定

对于拥塞控制来说,TCP 每条连接都需要维护两个核心状态:

  • 拥塞窗口(Congestion Window,cwnd**) 把一次性能够发送的数据包多少的窗口**称之为拥塞窗口

拥塞窗口 cwnd 变化规则:

  • 只要网络中没有出现拥塞,cwnd 增大
  • 网络中出现了拥塞,cwnd 减小
  • 慢启动阈值(Slow Start Threshold,ssthresh)

怎么知道当前网络是否出现了拥塞?

只要「发送方」没有在规定时间内接收到 ACK 应答报文,就是发生了超时重传,认为网络出现了拥塞

拥塞控制的控制算法?

拥塞控制主要是四个算法:

  • 慢启动
  • 拥塞避免
  • 拥塞发生
  • 快速恢复

MTU 最大传输单元

MSS(最大消息长度):为TCP数据包每次传输的最大数据分段大小,一般由发送端向对端TCP通知在每个分节能发送的最大TCP数据

# 慢开始

TCP 刚建立连接完成后,首先有个慢启动的过程,意思就是一点一点提高发送数据包的数量,如果一上来就发大量的数据,这不是给网络添堵吗?

慢启动的算法记住一个规则就行:当发送方每收到一个 ACK,拥塞窗口 cwnd 的大小就会加 1

发包的个数是指数性的增长

有一个叫慢启动门限 ssthresh (slow start threshold)变量

  • cwnd < ssthresh 时,使用慢启动算法
  • cwnd >= ssthresh 时,使用「拥塞避免算法」
  1. 连接建好的开始,初始化拥塞窗口cwnd大小为1,表明可以传一个MSS大小的数据

  2. 每收到一个ACK,cwnd大小加一,线性上升

  3. 每过了一个往返延迟时间RTT(Round-Trip Time),cwnd大小翻倍,乘以2,指数让升

  4. 还有一个ssthresh(slow start threshold),是一个上限,cwnd >= ssthresh时,进入“拥塞避免算法”

# 拥塞避免

拥塞窗口 cwnd 「超过」慢启动门限 ssthresh 进入拥塞避免

过了慢启动阈值后,拥塞避免算法可避免窗口增长过快导致窗口拥塞,而是缓慢的增加调整到网络的最佳值

进入拥塞避免算法后,规则是:每当收到一个 ACK 时,cwnd 增加 1/cwnd

一般来说,TCP拥塞控制默认 认为网络丢包是 由于网络拥塞导致,所以一般 TCP拥塞控制算法以丢包 作为网络进入拥塞状态的信号。对丢包有两种判定方式,

一种是超时重传RTO[Retransmission Timeout]超时

另一个是收到三个重复确认ACK

超时重传是TCP协议保证数据可靠性的一个重要机制,原理是在发送一个数据以后开启一个计时 器,一定时间内如果没有得到发送数据报的ACK报文,就重新发送数据,直到发送成功

但如果发送端接收到3个以上的重复ACK,TCP意识到数据发生丢失,需要重传。这个机制不需要等到重传定时器超时,所以叫超时 重传RTO[Retransmission Timeout]超时,TCP会重传数据包。TCP认为这种情况比较糟糕,反应也比较强烈:

发生丢包,将慢启动阈值ssthresh设置为当前cwnd的一半,即ssthresh = cwnd / 2

cwnd重置为1 进入慢启动过程是早期的处理办法,但是一丢包就一切重来,cwnd又重置为1,不利于网络数据的稳定传递

就这么一直增长后,网络慢慢进入了拥塞的状况,就会出现丢包现象,这时就需要 重传 丢失的数据包

当触发了重传机制,也就进入了「拥塞发生算法」

# 拥塞发生

当网络出现拥塞,会发生数据包重传,重传机制主要有两种:

  • 超时重传
  • 快速重传

发生超时重传的拥塞发生算法

发生了「超时重传」,就会使用拥塞发生算法

这时,ssthresh 和 cwnd 的值会变化:

  • ssthresh 设为 cwnd/2
  • cwnd 重置为 1

image-20220606075721243

接着,重新开始慢启动,慢启动会突然减少数据流。这真是一旦「超时重传」,马上回到解放前。这种方式太激进了,反应很强烈,会造成网络卡顿

就好像本来在秋名山高速漂移着,突然来个紧急刹车,轮胎受得了吗。。。

发生快速重传的拥塞发生算法

还有更好的方式,前面我们讲过「快速重传算法」。当接收方发现丢了一个中间包的时候,发送三次前一个包的 ACK,于是发送端就会快速地重传,不必等待超时再重传

TCP 认为这种情况不严重,因为大部分没丢,只丢了一小部分,则 ssthresh 和 cwnd 变化如下:

  • cwnd = cwnd/2 ,也就是设置为原来的一半
  • ssthresh = cwnd
  • 进入快速恢复算法

# 快速恢复

快速重传和快速恢复算法一般同时使用,快速恢复算法认为,你还能收到 3 个重复 ACK 说明网络也不那么糟糕,所以没有必要像 RTO 超时那么强烈

正如前面所说,进入快速恢复之前,cwnd 和 ssthresh 已被更新了:

  • cwnd = cwnd/2 ,设置为原来的一半
  • ssthresh = cwnd

然后,进入快速恢复算法:

  • 拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了)
  • 重传丢失的数据包
  • 如果再收到重复的 ACK, cwnd 增加 1
  • 如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh 的值,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,即再次进入拥塞避免状态

image-20220606075659094

没有像「超时重传」一夜回到解放前,而是还在比较高的值,后续呈线性增长

# 流量控制和拥塞控制?

流量控制:传输网络畅通但接收设备小容量

拥塞控制:内部拥塞是大容量接收设备

流量控制属于通信双方协商;拥塞控制涉及通信链路全局

流量控制需要通信双方各维护一个发送窗、一个接收窗,对任意一方,接收窗大小由自身决定,发送窗大小由接收方响应的TCP报文段中窗口值确定

拥塞控制的拥塞窗口大小变化由试探性发送一定数据量数据探查网络状况后而自适应调整

# TCP 缺陷?

  • 升级 TCP 工作困难
  • TCP 建立连接的延迟
  • TCP 存在队头阻塞问题
  • 网络迁移需要重新建立 TCP 连接

# 升级 TCP 工作困难

TCP协议在内核中实现,应用程序只能使用不能修改,若想要升级TCP只能升级内核

内核升级设计到底层软件和运行库的更新,我们的服务程序需要回归测试是否兼容新的内核版本,服务器的内核升级比较保守且缓慢

# TCP 建立连接延迟

基于TCP实现的应用协议,都需要先建立三次握手才能进行数据传输,比如HTTP1.1/1.1、HTTP/2、HTTPS

大多数网站都是使用的HTTPS,TCP三次握手之后,还需要经过TLS四次握手后,才能进行HTTP数据的传输,一定程度增加了数据传输的延迟

# TCP 存在队头阻塞问题

TCP是字节流协议,TCP层必须保证收到的字节数据完整且有序,如果序列号较低的TCP段在网络传输中丢失,即使序列号较高的TCP段已经被接收,应用层也无法从内核中读取到这部分数据

HTTP/2多个请求是跑在一个TCP连接中的,当TCP丢包时,整个TCP都要等待重传,会阻塞该TCP连接中的所有请求,所以 HTTP/2 队头阻塞问题就是TCP协议导致的

image-20220606075607940

# 网络迁移需重新建立 TCP 连接

基于 TCP 传输协议的 HTTP 协议,通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接

image-20220606075626906

当移动设备的网络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,就必须要断开连接,重新建立 TCP 连接

建立连接的过程包含 TCP 三次握手和 TLS 四次握手的时延,以及 TCP 慢启动的减速过程,给用户的感觉就是网络突然卡顿了一下,因此连接的迁移成本很高

# UDP 实现可靠传输?

TCP 天然支持可靠传输,为什么还需要基于 UDP 实现可靠传输呢?这不是重复造轮子吗?

# 通信数据转发程序

# 代理

代理是一种有转发功能的应用程序,它扮演了位于服务器和客户端“中间人”的角色,接收由客户端发送的请求并转发给服务器,同时接收服务器返回的响应并转发给客户端

基本行为——接收客户端发送的请求后转发给其他服务器。代理不改变请求URL,直接发送给前方持有资源的目标服务器

1649667894863

# 代理方法

# 缓存

代理转发响应时,缓存代理(Caching Proxy)预先将资源的副本(缓存)保存在代理服务器上。当代理再次接收到对相同资源的请求时,可以不从源服务器那里获取资源,而是将之前缓存的资源作为响应返回

# 透明代理

转发请求或响应时,不对报文做任何加工的代理类型被称为透明代理(Transparent Proxy)。反之,对报文内容进行加工的代理被称为非透明代理

# 网关

网关是转发其他服务器通信数据的服务器,接收从客户端发送来的请求时,它就像自己拥有资源的源服务器一样对请求进行处理。有时客户端可能都不会察觉,自己的通信目标是一个网关

1649667904860

# 隧道

隧道是在相隔甚远的客户端和服务器两者之间进行中转,并保持双方通信连接的应用程序

1649667911170

# HTTP请求方法

方法 描述
GET 请求指定的页面信息,返回实体主体
HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头,确认URI的有效性及资源更新的日期时间等
POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改
PUT 从客户端向服务器传送的数据取代指定的文档的内容
DELETE 请求服务器删除指定的页面
CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
OPTIONS 允许客户端查看服务器的性能;查询针对请求URI 指定的资源支持的方法
TRACE 回显服务器收到的请求,主要用于测试或诊断

# options方法?

browser自动发起

获取当前URL所支持的方法

检查服务器性能

# 💚 GET、POST

# GET

**不能 传中文,会**乱码!!

根据 RFC 规范,GET 是从服务器获取指定的资源,这个资源可以是静态的文本、页面、图片视频等

GET 请求的参数位置一般写在 URL 中,URL 规定只能支持 ASCII,浏览器会对 URL 的长度有限制(HTTP协议本身对 URL长度并没有做任何规定)

传送的数据量较小,不能大于2KB

# POST

根据 RFC 规范,POST 是根据请求负荷(报文body)对指定的资源做出处理

POST 请求携带数据的位置一般写在报文 body 中,数据可以是任意格式,只要与服务端协商好,且浏览器不会对 body 大小做限制

# 区别

幂等:多次执行相同的操作,结果都相同

安全:请求方法不会破坏服务器上的资源

  • 大多数浏览器限制url 2KB,大多数服务器处理 64 K url,GET可带 body 但不保证可被接收
  • GET产生一个TCP 数据包,POST 产生2个——有争议!!这个根代码和TCP协议栈有关,和HTTP 无关
GET: 浏览器一并发送 http header 和 data,服务器响应200
POST:浏览器先发送 header ,服务器响应100 continue ,browser再发送 data,响应200
1
2
  • 都是HTTP请求方式,HTTP 基于 TCP/IP ,没实质区别

  • 不携带参数时,最大区别是请求行不同

    1. GET:GET /uri HTTP/1.1
    2. POST:POST /uri HTTP/1.1
  • GET安全且幂等,可对数据缓存,缓存可以做到浏览器上(彻底避免浏览器发请求),也可以做到代理上(如nginx),可以保存为书签

  • POST是新增或提交数据,会修改服务器资源,不安全,不幂等。浏览器一般不缓存POST请求,也不能保存为书签

  • 从传输的角度来说,他俩都不安全,HTTP是明文传输,只要在网络节点抓包就能完整获取数据报文,只有HTTPS才能加密安全

get和post的区别本质上被浏览器/服务器限制,而不是HTTP协议限制

# GET参数写法固定?

RFC 并没规定 GET 请求不能带 body 。理论上,任何请求都可以带 body 。只是因为 RFC 定义的 GET 请求是获取资源,根据这个语义不需要用到 body

URL 中的查询参数也不是 GET 所独有,POST 请求的 URL 中也可以有参数

解析报文过程:获取TCP数据,正则从数据获取Header和Body,提取参数,也可以自己约定参数写法,只要后端能够解析出来就行

# POST比GET安全?

如果「安全」放入概念是指信息是否会被泄漏的话,虽然 POST 用 body 传输数据,GET 用 URL 传输,数据会在浏览器地址拦容易看到,但并不能说 GET 不如 POST 安全

HTTP 传输的内容都是明文,在浏览器地址拦看不到 POST 提交的 body 数据,但只要抓个包就都能看到

要避免传输过程中数据被窃取——使用 HTTPS 协议,所有 HTTP 的数据都被加密传输

# GET长度限制?

HTPP协议没有对Body和URL长度限制,是浏览器和服务器原因

服务器原因是处理长URL消耗多的资源(防止恶意构造长的URL),为了性能和安全

# POST产生两个TCP数据包?

header和body分开发送是部分浏览器请求方法,不属于post必然行为

100 continue为了在发送body之前查看服务器是否接受这个实体,属于优化

大多数是尽量在TCP包中将请求发出去,但也确实存在先发header,再发body的情况。具体是多少个TCP包,这个不关HTTP的事,是OS TCP协议栈和代码的问题

# ⏩ HTTP

# 优点

  1. 简单

    • HTTP 基本报文格式是 header + body,头部信息也是 key-value 简单文本的形式,易于理解,降低了学习和使用门槛
  2. 灵活 易扩展

    • HTTP协议里的各类请求方法、URI/URL、状态码、头字段等每个组成要求都没有被固定死,允许开发人员自定义和扩充
    • HTTP 由于工作在应用层( OSI 第七层),它下层可以随意变化
    • HTTPS 就是在 HTTP 与 TCP 层之间增加了 SSL/TLS 安全传输层,HTTP/3 甚至把 TCP 层换成了基于 UDP 的 QUIC
  3. 应用广泛和跨平台

    • HTTP 的应用范围非常广泛,从台式机浏览器到手机上的各种 APP,从看新闻到购物、理财,HTTP 的应用遍地开花,天然具有跨平台优越性
  4. 可靠

    • HTTP对传输数据进行一层包装,加上一个头,调用API,通过TCP/IP协议发送和接收
  5. 使用 请求-应答 通信模式

  6. 无状态,client和server永远处于“无知”状态,每次请求和答复独立。协议不要求server或client记录请求的相关信息

    TCP有状态:CLOSED——ESTABLISHED——FIN-WAIT——CLOSED。HTTP 1.1中总是默认启动keep-alive长连接机制

# 缺点

  1. 明文传输,内容可能被窃听

明文意味着在传输过程中的信息,方便阅读。正是这样,HTTP 所有信息都暴露在了光天化日下,相当于信息裸奔。在传输的漫长的过程中,信息的内容都毫无隐私可言,很容易就能被窃取,如果里面有账号密码信息,那号没了

  1. 不安全,无法验证通信双方身份,也不能判断报文是否修改

HTTP 比较严重的缺点是不安全:

  • 通信使用明文(不加密),内容可能被窃听。比如,账号信息容易泄漏,那你号没了
  • 不验证通信方的身份,因此有可能遭遇伪装。比如,访问假的淘宝、拼多多,那你钱没了
  • 无法证明报文的完整性,所以有可能已遭篡改。比如,网页上植入垃圾广告,视觉污染,眼没了

HTTP 的安全问题,可以用 HTTPS 解决,通过引入 SSL/TLS 层,在安全上达到极致

  1. 无论是谁发送来的请求都会响应
  • 无法确定请求发送至目标的Web服务器是否是按真实意图返回响应的那台服务器。有可能是已伪装的Web服务器
  • 无法确定响应返回到的客户端是否是按真实意图接收响应的那个客户端。有可能是已伪装的客户端
  • 无法确定正在通信的对方是否具备访问权限。因为某些Web服务器上保存着重要的信息,只想发给特定用户
  • 无法判定请求是来自何方、出自谁手
  • 即使是无意义的请求也会照单全收。无法阻止海量请求下的DoS攻击(Denial of Service,拒绝服务攻击)
  1. 无状态双刃剑
  • 无状态的好处,服务器不会记忆 HTTP 的状态,所以不需要额外资源记录状态信息,能减轻服务器的负担,能够把更多的 CPU 和内存用来对外提供服务

  • 无状态的坏处,既然服务器没有记忆能力,在完成有关联性的操作时会非常麻烦

例如登录->添加购物车->下单->结算->支付,这系列操作都要知道用户的身份才行。但服务器不知道这些请求是有关联的,每次都要问一遍身份信息

这样每操作一次,都要验证信息,这样的购物体验还能愉快吗?

对于无状态的问题,解法方案有很多种,其中比较简单的方式用 Cookie 技术

Cookie 通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态

相当于,在客户端第一次请求后,服务器会下发一个装有客户信息的「小贴纸」,后续客户端请求服务器的时候,带上「小贴纸」,服务器就能认得了

图片

# 一个TCP连接中HTTP请求可一起发送么

(比如一起发三个请求,再三个响应一起接收)?

HTTP1.1存在一个问题,单个TCP连接在同一时刻只能处理一个请求。即两个请求的生命周期不能重叠,任意两个HTTP请求从开始到结束的时间在同一个TCP连接中不能重叠

在 HTTP/1.1 存在 Pipelining 技术可以完成多个请求同时发送,但由于浏览器默认关闭,所以认为这是不可行的

在 HTTP2 中由于 Multiplexing (多路复用)特点的,多个 HTTP 请求可以在同一个 TCP连接中并行进行

在 HTTP/1.1 时代,浏览器如何提高页面加载效率呢?主要有下面两点:

  1. 维持和服务器已经建立的 TCP 连接,在同一连接上顺序处理多个请求
  2. 和服务器建立多个 TCP 连接

# HTTP 0.9

  • 只支持get
  • 不支持请求头
  • 只能传输纯文本
  • 无状态连接

# HTTP1.0、HTTP1.1

image-20220730200357046

# HTTP1.0

与服务器只保持短暂的连接,每次请求都要与服务器建立一个TCP连接

  • 响应不仅限文本
  • 支持响应/请求头
  • 默认短连接,增加keep-alive关键字由短链接变成长连接
  • 支持get post head

# HTTP 1.1性能?

  • 新增options、put、delete、trace和connect

  • 增加host字段

  • 长连接

(Persistent Connection)在一个TCP连接上可传送多个HTTP请求和响应,减少建立、关闭连接的消耗和延迟。默认开启Connection : keep-alive

只要任意端没有明确提出断开连接,则保持 TCP 连接状态

如果某个 HTTP 长连接超过一定时间没有任何数据交互,服务端主动断开连接

  • 管道网络传输(请求流水线处理)

HTTP/1.1 采用长连接的方式,使得管道(pipeline)网络传输成为可能

在同一个 TCP 连接里面,客户端可发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,减少整体响应时间

举例来说,客户端需要请求两个资源。以前的做法是,在同一个 TCP 连接里面,先发送 A 请求,等待服务器做出回应,收到后再发出 B 请求。管道机制则是允许浏览器同时发出 A 请求和 B 请求, 但是服务器必须按照接收请求的顺序发送对这些管道化请求的响应

注意,是按照服务端收到的请求顺序响应,不管哪个请求是先发送,假设客户端先发送 A 请求,后发送 B 请求,如果服务端先收到 B 请求,就先响应 B 请求,再响应 A 请求,但是假设处理 B 请求耗时较长,请求 A 的响应就会被阻塞,称为「队头堵塞」

所以,HTTP/1.1 管道解决了请求的队头阻塞,但是没有解决响应的队头阻塞

  • 队头阻塞

「请求 - 应答」的模式加剧了 HTTP 的性能问题

当顺序发送的请求序列中的一个请求因为某种原因被阻塞,在后面排队的所有请求也一同被阻塞,会导致客户端一直请求不到数据——「队头阻塞」,好比上班的路上塞车

总之 HTTP/1.1 的性能一般般

# HTTP1.1相比HTTP1.0

  1. 缓存处理,引入更多缓存头控制缓存策略。HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入更多的缓存控制策略例如Entity tag,If-Unmodified-Since,If-Match,If-None-Match等更多可供选择的缓存头控制缓存策略
  2. 带宽优化及网络连接的使用,增加断点续传功能
  3. 错误通知的管理:新增24个错误状态码,如409(conflict)表示请求资源与资源当前状态冲突、410(Gone)表示服务器上某个资源被永久性删除
  4. Host头处理。随着虚拟主机技术的发展,一台物理服务器上可以存在多个虚拟主机且共享同一个IP。HTTP 1.1请求和响应都支持host头,请求消息中如果缺少host,400(Bad Request)
  5. 长连接,改善HTTP1.0短连接造成的性能开销
  6. 支持管道网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,减少整体响应时间

# 二者存在问题:

  1. HTTP传输数据,每次都要3次握手建立连接,增加大量延迟
  2. 明文传输
  3. header携带内容过大,增加传输成本
  4. HTTP1.1支持keep-alive,但是keep-alive使用多了同样给服务端带来大量性能压力,因为文件被请求后,服务端需要保持不必要的连接很长时间

# HTTP1.1性能瓶颈

  1. 请求/响应头部未经压缩就发送,首部信息越多延迟越大,只能压缩Body部分
  2. 发送冗长首部.每次发送相同的首部造成浪费
  3. 服务器按请求的顺序响应,如果服务器响应慢,会导致客户端一直请求不到数据——队头阻塞
  4. 没有请求优先级控制
  5. 请求只能从客户端开始,服务器只能被动响应

# SPDY-HTTP1.x优化

SPDY位于HTTP之下,TCP和SSL之上,可轻松兼容老版本的HTTP协议,也可使用已有的SSL功能

1649667923347

# 特点

  • 降低延迟

针对HTTP高延迟的问题,SPDY采取了多路复用(multiplexing)

多路复用通过多个请求stream共享一个tcp连接,解决了HOL blocking(队头阻塞)问题,降低延迟同时提高带宽利用率

  • 请求优先级(request prioritization)

多路复用的连接共享机制可能导致关键请求被阻塞

SPDY允许给每个request设置优先级,重要请求优先得到响应

  • header压缩

减少包的大小和数量,酱紫通信产生的数据包数量和发送的字节数就更少了

  • 基于HTTPS的加密协议传输,提高传输数据的可靠性
  • 服务端推送(Server push)

采用了SPDY的网页,例如我的网页有一个style.css的请求,在客户端收到style.css数据的同时,服务端会将style.js的文件推送给客户端,当客户端再次尝试获取style.js时就可以直接从缓存中得到,不用再次请求

  • 多路复用。通过单一的TCP连接,可以无限制处理多个HTTP请求
  • 服务器提示功能。服务器可主动提示客户端请求所需的资源。在客户端发现资源前就获取资源的存在,在资源已缓存的情况下,避免发送请求

# WebSocket

Websocket和socket——雷锋和雷峰塔

网络传输协议,浏览器和服务端 全双工通讯的网络技术,位于应用层

节省服务器资源和带宽达到实时通迅

客户端和服务器只需完成一次握手,两者就可创建持久性连接,并进行双向数据传输

# 特点

  1. 二进制帧。语法语义和HTTP完全不兼容,对比HTTP2,WebSocket侧重于 实时通信,HTTP2侧重于提高传输效率,不存在多路复用,优先级等特性;不需要服务器推送

# 应用

websocket完美继承 TCP 的全双工能力, 还贴心 提供了解决粘包的方案。 适用于需要服务器和客户端(浏览器)频繁交互的大部分场景。 网页/小程序游戏,网页聊天室, 类似飞书 的网页协同办公软件

使用websocket协议的网页游戏里,怪物移动以及攻击玩家的行为是服务器逻辑产生 ,对玩家产生的伤害等数据, 由服务器主动发送给客户端,客户端获得数据后展示效果

  • 弹幕
  • 媒体聊天
  • 协同编辑
  • 基于位置的应用
  • 体育实况更新

# HTTP不断轮询

伪服务器推的方式——前端不断定时发请求到服务器,服务器收到请求后给客户端响应

场景:扫码登录

问题:

  1. 满屏的HTTP请求,消耗带宽增加服务器负担
  2. 最坏情况需要等1~2s触发请求,跳转页面,出现卡顿

# 长轮询

若http请求将超时设置的很大,在30s内只要服务器收到了扫码请求,就立马返回给客户端,若超时则发下一个请求

场景:百度网盘

长轮询——发起一个请求,在较长时间内等待服务器响应

# Websocket

# ✅ HTTP 2.0

更快 更稳定 更简单

1649990622271

# 特性

HTTP/2 协议基于 HTTPS

HTTP2.0可以说是SPDY的升级版本,与SPDY的区别如下:

  1. HTTP2.0支持明文HTTP传输,而SPDY强制使用HTTPS
  2. HTTP2.0消息头压缩算法使用HPACK,而SPDY使用DEFLATE

HTTP2.0主要目标——改进传输性能,实现低延迟和高吞吐量

HTTP2.0升级改造需要考虑:

  1. HTTP2.0支持非HTTPS,但主流浏览器如chrome、Firefox还是只支持基于TLS部署的HTTP2.0协议,所以升级HTTP2.0还是要先升级HTTPS
  2. 升级HTTPS后,如果使用NGINX,只需要在配置文件中启动相应的协议就可
  3. HTTP2.0完全兼容HTTP1.x,对于不支持HTTP2.0的浏览器,NGINX自动向下兼容

# 二进制分帧

HTTP/2 不像 HTTP/1.1 纯文本形式的报文,而是全面采用二进制格式**,头信息和数据体都是二进制,统称为帧(frame):**头信息帧(Headers Frame)和数据帧(Data Frame)

帧——HTTP/2 通信最小单位,每个帧都包含帧头,至少会标识出当前帧所属的数据流

HTTP/2 连接是永久的,仅需要每个来源 一个连接

1649991372265

对人不友好,但是对计算机友好,因为计算机只懂二进制,收到报文后,无需再将明文的报文转成二进制,而是直接解析二进制报文,增加了数据传输的效率

(因为是新增的二进制分帧层,所以叫2.0)

不改变HTTP语义,HTTP方法、状态码、URL及首部字段。改进传输性能,实现低延迟和高吞吐量

HTTP1.x解析基于文本,文本展现形式多样,要做到健壮性考虑的场景必然很多,二进制则只有0和1,更高效健壮

# 首部压缩

HTTP/2 会压缩头(Header)如果同时发出多个请求,他们的头一样或是相似,协议会消除重复的部分

HPACK算法:客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,提高速度

HTTP 1.x无首部压缩,Gzip只对请求体压缩

SPDY和HTTP 2.0都支持首部压缩。使头部帧最大程度复用,减少头部大小,减少内存和流量

比如:第一次请求,包含头部各种信息,后来又发送另外请求,发现大部分字段可以复用,一次只发送一个当前请求特有的头部帧即可

避免重复header传输

  1. HTTP2.0会压缩首部元数据,在client和server使用首部表跟踪和存储之前发送的健值对,对于相同数据,不需每次请求响应都发送
  2. 所有header必须全部小写,而且请求行要独立为健值对(即header+值)

# 多路复用

HTTP 1.0:建立连接,请求数据完毕之后立即关闭连接

后采用keep-alive模式使得可以复用连接而不断开,可利用这次连接继续请求

缺点:必须等到server返回上一次的请求数据才进行下一次请求

Q:遇到一个请求很久没有响应,后面的请求只能等待?

HTTP/2 可以在一个连接中并发请求,不用按照顺序一一对应

多路复用(MultiPlexing),即连接共享,每一个request都是用作连接共享机制。每一个request对应一个id,一个连接上可以有多个request,每个连接的request可以随机混杂在一起,接收方根据request的id将request归属到不同服务端请求里。客户端只需要一个连接就可以加载一个页面

移除了 HTTP/1.1 中的串行请求,不需要排队等待,不会再出现「队头阻塞」问题,降低了延迟,大幅度提高了连接利用率

举例来说,在一个 TCP 连接里,服务器收到了客户端 A 和 B 的两个请求,如果发现 A 处理过程非常耗时,于是回应 A 请求已经处理好的部分,接着回应 B 请求,完成后,再回应 A 请求剩下的部分

优点:

  1. 并行交错发送请求,请求之间互不影响
  2. TCP连接一旦建立可并行发送请求
  3. 消除不必要延迟,减少页面加载时间
  4. 可最大程度利用HTTP 1.x

# 请求优先级

server根据流的优先级控制资源分配,响应数据准备好后,把优先级最高的帧发送给client。browser发现资源时立即分派请求,指定每个流的优先级,让服务器决定最优的响应次序,这时请求不用排队,节省时间,最大限度利用连接

# 流量控制

流:不改变协议,允许采用多种流量控制算法

特点:

  1. 流量基于HTTP连接的每一跳进行,不是端到端控制
  2. 流量基于窗口更新帧进行,接收方可广播准备接收字节
  3. 流量控制有方向,接收方根据自身情况控制窗口大小
  4. 流量控制可由接收方禁用
  5. 只有data帧服从流量控制,其他不会消耗控制窗口的空间

# 服务端推送

HTTP/2 一定程度上改善了传统的「请求 - 应答」工作模式,服务不再被动响应,也可以主动向客户端发送消息

server push通过推送那些它认为客户端将会需要使用到的内容到客户端缓存中,避免往返的延迟

# 数据流

HTTP/2 的数据包不是按顺序发送,同一个连接里面连续的数据包,可能属于不同回应。因此,必须要对数据包做标记,指出它属于哪个回应

HTTP/2 中每个请求或相应的所有数据包,称为一个数据流(Stream)。每个数据流都标记着一个独一无二的编号(Stream ID),不同 Stream 的帧可乱序发送(因此可并发不同Stream ),因为每个帧头部携带 Stream ID 信息,所以接收端可以通过 Stream ID 有序组装成 HTTP 消息

客户端和服务器双方都可以建立 Stream, Stream ID 也有区别,客户端建立的 Stream 必须是奇数号,而服务器建立的 Stream 必须是偶数号

图片

客户端可以指定数据流的优先级。优先级高的请求,服务器先响应 该请求

# 缺陷

HTTP/2 通过 Stream 的并发能力,解决了 HTTP/1 队头阻塞的问题,看似很完美,但是 HTTP/2 还是存在“队头阻塞”的问题,只不过问题不是在 HTTP 这一层面,而是在 TCP 这一层

HTTP/2 基于 TCP 协议传输数据,TCP 是字节流协议,TCP 层必须保证收到的字节数据完整且连续,这样内核才会将缓冲区里的数据返回给 HTTP 应用,当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据—— HTTP/2 队头阻塞问题

1649991718193

图中发送方发送了很多个 packet,每个 packet 都有自己的序号,可认为是 TCP 的序列号, packet 3 在网络中丢失了,即使 packet 4-6 被接收方收到后,由于内核中的 TCP 数据不连续,接收方的应用层无法从内核中读取,只有等到 packet 3 重传后,接收方的应用层才可以从内核中读取到数据

所以,一旦发生丢包现象,会触发 TCP 重传机制,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传

# HTTP3

Http3.0 相对于 Http2.0 是脱胎换骨的改变!

HTTP1.1和HTTP1.2都有队头阻塞的问题

  • HTTP1.1中的管道(pipeline)解决了请求的对头阻塞,但是没有解决响应的队头阻塞,因为服务端需要按顺序响应收到的请求,如果服务端处理某个请求消耗的时间比较长,只能等相应完这个请求后, 才能处理下一个请求。——HTTP 层队头阻塞
  • HTTP/2 虽然通过多个请求复用一个 TCP 连接解决了 HTTP 的队头阻塞 ,但一旦发生丢包,就会阻塞所有 HTTP 请求——TCP 层队头阻塞

HTTP/2 队头阻塞的问题是因为 TCP,所以 HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP!!

1650001214670

UDP 不管顺序,也不管丢包,不会像 HTTP/2 出现队头阻塞问题

UDP 不可靠传输,但基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠传输

# 特性

# 连接迁移

# 无队头阻塞

# 自定义拥塞控制

# 前向安全和前向纠错

# 为什么HTTP3.0使用UDP?

# 🌰 HTTPS=HTTP+SSL/TLS

HTTPS=HTTP+加密+认证+完整性保护

(HTTP Secure)

202205101156387

HTTPS是加强版的HTTP,是在HTTP和TCP间建立了一个中间层(安全层),进行加密,TCP必须将数据包解密才能传给上面的HTTP

header+body整个都加密,啥都看不到

URL信息在header中,自然被加密

图片

HTTPS加密的内容有??

  • 请求头
  • 请求路劲
  • 请求参数

不会加密 请求域名!!!

# SSL/TLS

“Secure Sockets Layer”,叫做“安全套接层”(依靠整数验证服务器身份)一种用于加密和验证应用程序和web服务器间发送的数据的协议

标准化之后的名称改为 TLS(“Transport Layer Security”),叫做“传输层安全协议”

公钥加密,私钥解密

# 作用

认证用户和服务,加密数据,维护数据完整性

SSL证书验证服务器身份,并为它们之间的通信进行加密

SSL/TLS 协议基本流程:

  • 客户端向服务器索要并验证服务器的公钥
  • 双方协商生产「会话秘钥」
  • 双方采用「会话秘钥」加密通信

# SSL/TLS的四次握手

image-20220730153609012

SSL/TLS 的「握手阶段」涉及四次通信,可见下图:

1649989444956

服务端生成第一随机数和第二随机数以及自己的公钥发送给客户端,客户端用服务端的公钥锁上预主秘钥(第三随机数),发送给服务端,服务端收到后用自己的私钥解密,取出欲主密钥,后面2者完全使用欲主密钥以对称加密的方式通信

欲主密钥——会话秘钥

SSL/TLS 协议建立的流程:

  1. ClientHello

客户端向服务器发起加密通信请求—— ClientHello 请求

客户端主要向服务器发送以下信息:

(1)支持的 SSL/TLS 协议版本,如 TLS 1.2 版本

(2)第一随机数——客户端生产的随机数(Client Random),用于后面生成「会话秘钥」条件之一

(3)**客户端支持的加密方法,**如 RSA 公钥加密,此时是明文传输

(4)支持的压缩算法

  1. SeverHello

服务器收到客户端请求后,向客户端发出响应—— SeverHello。服务器回应:

(1)确认SSL/TLS协议版本,如果浏览器不支持,关闭加密通信

(2)第二随机数——服务器生产的随机数(Server Random),是生产「会话秘钥」的条件之一

(3)确认使用加密算法

(4)服务器证书(证书包含网站地址,非对称加密公钥,证书领发机构等信息)

  1. 客户端回应

客户端收到服务器的回应之后,通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书真实性(颁发机构是否合法,证书中包含网址是否和正在访问的一样),证书过期,会给一个警告,是否选择继续通信

如果证书没有问题,客户端从数字证书中取出服务器的公钥,使用它加密报文,向服务器发送:

(1)第三随机数(pre-master key),用于服务器公钥加密

(2)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信

(3)客户端握手结束通知,这一项同时把之前所有内容发生改变的数据做个摘要,供服务端校验

服务器和客户端有了这三个随机数(Client Random、Server Random、pre-master key),接着用协商的加密算法,各自生成本次通信的「会话秘钥」

为啥是3个随机数?

一个伪随机可能不完全随机,可是3个随机数就很接近随机了,每增加一个自由度,随机性增加的可不是一!!

  1. 服务器的最后回应

服务器收到客户端的第三个随机数(pre-master key)之后,通过协商的加密算法,计算出本次通信的「会话秘钥」

然后,向客户端发送最后的信息:

(1)加密通信算法改变通知,随后的信息都将用「会话秘钥」加密通信

(2)服务器握手结束通知,同时把之前所有内容的发生改变的数据做个摘要(内容的hash值),供客户端校验

至此,整个 SSL/TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,完全使用普通的 HTTP 协议,只不过用「会话秘钥」加密内容

# 🍪HTTPS保证传输安全?

# TLS1.0

使用RSA密钥交换算法

# TLS.12

使用ECDHE算法

# 🔥 HTTPS、HTTP

简单来看,https与http的区别就是: 在请求前,会建立ssl链接,确保接下来的通信都是加密的,无法被轻易截取

  1. HTTPS 需要申请数字证书(去 CA 申请),保证服务器的身份可信
  2. HTTPS在TCP和HTTP应用层间加入了SSL/TLS安全协议,是HTTP的加密版本;HTTP 是超文本传输协议,明文传输不安全
  3. HTTP 端口 80; HTTPS 端口 443
  4. HTTP 无状态连接,建立连接相对简单,三次握手后即可进行报文传输.HTTPS在TCP三次握手之后,还需进行SSL/TLS的握手过程,才可进入加密报文传输
  5. HTTPS 协议 由 SSL+HTTP 构建,更安全
  6. HTTPS提供
    • 数据完整性
    • 隐私性
    • 身份认证
    • 不可否认性

# HTTPS解决啥问题

图片

# HTTP存在风险

  1. 窃听风险,如通信链路上可以获取通信内容,用户号容易没
  2. 篡改风险,如强制植入垃圾广告,视觉污染,用户眼容易瞎
  3. 冒充风险,如冒充淘宝网站,用户钱容易没

# HTTPS 在 HTTP 与 TCP 层间加入SSL/TLS 协议,解决上述风险

  1. 信息加密:交互信息无法被窃取,但你的号会因为「自身忘记」账号而没
  2. 校验机制:无法篡改通信内容,篡改了就不能正常显示,但百度「竞价排名」依然可以搜索垃圾广告
  3. 身份证书:证明淘宝是真的淘宝网,但你的钱还是会因为「剁手」而没

# HTTPS 如何解决上面三个风险?

  1. 混合加密实现信息的机密性,解决了窃听的风险
  2. 摘要算法实现完整性,它能够为数据生成独一无二的「指纹」,用于校验数据的完整性,解决了篡改的风险
  3. 将服务器公钥放入到数字证书中,解决了冒充的风险(身份认证)
  4. 数字签名:不可否定。内容摘要算法得到摘要,私钥加密摘要,对方使用对应公钥解密,得到摘要,再和自己得到的服务器提供的原文摘要对比,一致说明这个内容就是原服务器提供的,由证书说明了服务器的身份

image-20220730153532152

# 混合加密

image-20220601155454154

对称加密——“加密”和“解密”使用【相同的】密钥

a发给b的文件需要加密,a用锁锁住文件发给b,然后再把钥匙发给b,b拿到钥匙和文件,解锁

非对称加密——加密 和 解密 使用不同的 密钥 (消耗大)

a发给b的文件需要加密,b把自己的锁发给a,a锁好后把文件发给b,b的钥匙一直都在自己手上,然后用自己的钥匙(私钥)解自己的锁(公钥),不用担心钥匙在传递过程中被窃取

公钥可以公开给任何人使用,私钥需要保密。公钥加密后只能用私钥解密,相反,私钥加密后只能用公钥解密

image-20220601155902815

图片

通过混合加密的方式保证信息的机密性,解决了窃听的风险

HTTPS 采用对称加密和非对称加密结合的「混合加密」方式:

  1. 在通信建立前采用非对称加密的方式交换「欲主秘钥」,后续就不再使用非对称加密
  2. 在通信过程中全部使用对称加密的「会话秘钥」的方式加密明文数据

采用「混合加密」方式的原因:

  • 对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换
  • 非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢

image-20220601155925914

非对称加密本质是为了防止私钥加密数据外传

image-20220601160014858

🌰网站保管私钥,在网上任意分发公钥,你想要登录网站只要用公钥加密就行了,密文只能由私钥持有者才能解密。而黑客因为没有私钥,无法破解密文

上述的方法解决了数据加密,在网络传输过程中,数据有可能被篡改,黑客可以伪造身份发布公钥,如果你获取到假的公钥,那么混合加密也并无多大用处,你的数据扔被黑客劫持

因此,在上述加密的基础上仍需加上完整性、身份验证的特性,实现真正的安全——摘要算法

# 摘要算法

实现完整性,为数据生成独一无二的「指纹」,校验数据的完整性,解决了篡改的风险

可以理解为一种特殊的压缩算法(生成hash值),把任意长度数据 压缩 成固定长度,独一无二 的摘要 字符串,就像是给这段数据生成了一个数字 指纹

1649984915924

客户端在发送明文之前通过摘要算法算出明文的「指纹」,发送的时候把「指纹 + 明文」一同加密成密文后,发送给服务器,服务器解密后,用相同的摘要算法算出发送过来的明文,通过比较客户端携带的「指纹」和当前算出的「指纹」做比较,若「指纹」相同,说明数据完整

# 数字签名

数字签名确定消息确实是由发送方签名并发出来,因为别人假冒不了发送方的签名

私钥加密,公钥解密!

如果想篡改,必须篡改原文信息后 私钥加密 才能得到原来的效果,可惜私钥不公开

签名和公钥一样完全公开,任何人都可以获取。但这个签名只有用私钥对应的公钥才能解开,拿到摘要后,再比对原文验证完整性,就可以像签署文件一样证明消息确实是你发的

image-20220601160039130

和消息本身一样,因为谁都可以发布公钥,我们还缺少防止黑客伪造公钥的手段,也就是说,怎么判断这个公钥就是你的公钥

这时候就需要一个第三方——证书验证机构CA

# 数字证书

数字证书作用:

  1. 服务器向浏览器证明自己的身份
  2. 把公钥传给服务器

客户端先向服务器端索要公钥,公钥加密信息,服务器收到密文后,用自己的私钥解密

这就存在问题,如何保证公钥不被篡改?

所以需要借助第三方权威机构 CA (数字证书认证机构),将服务器公钥放在数字证书(由数字证书认证机构颁发)中,只要证书是可信的,公钥就是可信的

1649985284588

  1. 服务器的运营人员向数字证书认证机构提出公开密钥的申请
  2. 数字证书认证机构在判明提出申请者的身份之后,会对已申请的公开密钥做数字签名
  3. 分配这个已签名的公开密钥,将该公开密钥放入公钥证书绑定在一起
  4. 服务器会将这份由数字证书认证机构颁发的数字证书发送给客户端,以进行非对称加密方式通信

接到证书的客户端使用数字证书认证机构的公开密钥,对证书上的数字签名进行验证,一旦验证通过,则证明:

  • 认证服务器的公开密钥的是真实有效的数字证书认证机构
  • 服务器的公开密钥值得信赖

# HTTPS中间人攻击

客户端和服务器之间的桥梁、双向获取并且篡改信息

WX20191126-212406@2x.png

标准回答

攻击者通过与客户端和客户端的目标服务器同时建立连接,作为客户端和服务器的桥梁,处理双方的数据,整个会话期间的内容几乎完全被攻击者控制。攻击者可以拦截双方的会话并且插入新的数据内容

加分回答

中间人攻击的过程:

  1. 本地请求被劫持,所有请求均发送到中间人服务器
  2. 中间人服务器返回中间人自己的证书
  3. 客户端创建随机数,通过中间人证书中的公钥加密 传送给中间人,凭随机数构造对称加密对传输内容加密传输
  4. 中间人拥有客户端返回的随机数,可以对内容解密
  5. 中间人以客户端的请求内容向真的服务器发送请求
  6. 服务器通过建立的通道返回加密后的数据
  7. 中间人对加密算法内容解密
  8. 中间人对内容加密传输
  9. 客户端通过和中间人建立的对称加密算法对返回数据解密

缺少证书的验证,客户端完全不知道自己的网络被拦截,数据被中间人窃取

# HTTPS一定安全?

HTTPS 协议本身到目前为止没有任何漏洞,即使成功进行中间人攻击,本质是利用客户端漏洞(用户点击继续访问/被恶意导入伪造根证书),并不是 HTTPS 不够安全

双向认证,客户端验证服务端身份,服务端也会验证客户端身份

image-20220928083831824

# 🌰 DNS 解析

将主机名转换为IP地址

  1. 一个由分层的DNS服务器实现的分布式数据库
  2. 一个使得主机能查询分布式数据库的应用层协议

# 域名

img

img

例如www.xxx.com,www为三级域名、xxx为二级域名、com为顶级域名(TLD-top level domain),系统为用户做了兼容,域名末尾的根域名.一般不需要输入

img

还有电脑默认的本地域名服务器

# 分布式

世界上没有一台DNS服务器拥有因特网上所有主机的映射,每台DNS只负责部分映射

# 本地DNS服务器

本地DNS服务器起着代理的作用,负责将该请求转发到DNS服务器层次结构中

# 递归、迭代查询

  • 递归查询:如果 A 请求 B,那么 B 作为请求的接收者一定要给 A 想要的答案

img

  • 迭代查询:如果接收者 B 没有请求者 A 所需要的准确内容,接收者 B 将告诉请求者 A,如何去获得这个内容,但是自己并不去发出请求

img

  1. 浏览器根据地址去缓存查找DNS解析记录,没有的话,浏览器查找OS中是否有该域名的DNS解析记录
  2. 缓存过期或没有记录,浏览器向域名服务器发请求解析域名
  3. 主机m向本地DNS服务器发送一个DNS查询报文,其中包含期待被转换的主机名a.b.com
  4. 本地DNS~无法解析,则将该报文转发到根DNS~
  5. 该根~注意到com前缀,便向本地DNS服务器返回com对应的顶级域名DNS服务器(TLD)的IP地址列表
  6. 本地DNS~则向其中一台TLD服务器发送查询报文
  7. 该TLD服务器注意到b.com前缀,于是向本地DNS服务器返回权威DNS服务器的IP地址
  8. 本地DNS服务器又向其中一台权威DNS服务器发送查询报文
  9. 终于,该权威服务器返回了a.b.com的IP地址
  10. 本地DNS服务器将a.b.com跟IP地址的映射返回给主机m.n.com,m.n.com就可以用该IP向a.b.com发送请求啦

img

主机向本地DNS服务器dns.n.com发出的查询是递归查询,这个查询是主机m.n.com以自己的名义向本地DNS服务器请求想要的IP映射,且本地DNS服务器直接返回映射结果到主机

**后继查询为迭代查询,**包括本地DNS 服务器向根 DNS 服务器发送查询请求、本地 DNS 服务器向 TLD 服务器发送查询请求、本地 DNS 服务器向权威 DNS 服务器发送查询请求,所有的请求都是由本地 DNS 服务器发出,所有的响应都是直接返回给本地 DNS 服务器。

解析结束,撒花✿✿ヽ(°▽°)ノ✿

# 所有 DNS 查询都必须遵循递归 + 迭代 ?

不是

理论上,任何 DNS 查询既可以是递归的,也可以是迭代的

TLD 一定知道权威 DNS 服务器的 IP 地址吗?

不一定,有时 TLD 只是知道中间的某个 DNS 服务器,再由这个中间 DNS 服务器去找到权威 DNS 服务器。这种时候,整个查询过程就需要更多的 DNS 报文

# DNS 优化和应用

# DNS缓存

在一个 DNS 查询的过程中,当某一台 DNS 服务器接收到一个 DNS 应答(例如,包含某主机名到 IP 地址的映射)时,它就能够将映射缓存到本地,下次查询就可以直接用缓存

有了缓存,大多数 DNS 查询都绕过了根 DNS 服务器,需要向根 DNS 服务器发起查询的请求很少

DNS存在多级缓存,从离浏览器的距离**排序的话**,有以下几种:

  • 浏览器缓存

  • 系统缓存

  • 路由器缓存

  • ISP(运营商) DNS缓存(本地服务器缓存)

  • 根域名服务器缓存

  • 顶级域名服务器缓存

  • 主域名服务器缓存

# 负载均衡

(DNS重定向) DNS负载均衡技术——在DNS服务器中为同一个主机名配置多个IP地址

简单说:用户发起的请求都指向调度服务器(反向代理服务器,如安装了nginx控制负载均衡),然后调度服务器根据实际的调度算法,分配不同的请求给对应集群中的服务器执行,调度器等待实际服务器的HTTP响应,并将它反馈给用户

# CDN(Content Delivery Network)

利用DNS的重定向技术,DNS服务器会返回一个跟 用户最接近的点的IP地址给用户,CDN节点的服务器负责响应用户的请求,提供所需的内容

# dns-prefetch

DNS Prefetch 是一种 DNS 预解析技术。当浏览网页时,浏览器会在加载网页时对网页中的域名进行解析缓存,这样在你单击当前网页中的连接时就无需进行 DNS 的解析,减少用户等待时间,提高用户体验

# 为啥使用UDP?

因为UDP快!UDP的DNS协议只要一个请求一个应答就好

# 解析不存在的域名?

如果域名 不存在,浏览器还是会从DNS那里解析一下,发现自己 操作系统 本地缓存都没有,CDN也没有,根域名 顶级域名 权威域名 非权威域名都没有

DNS解析失败,不会进入HTTP请求流程,不会有状态码错误,只会返回DNS解析错误信息

# others

# TCP/IP协议族?

TCP/IP协议将**应用层,表示层,会话层合并为应用层,**物理层和数据链层合并为网络接口层

TCP/IP协议指的是由 FTP SMTP TCP UDP IP ARP 等协议构成的协议集合

TCP/IP,传输控制协议/网际协议

  • TCP(传输控制协议)

一种面向连接的、可靠的、基于字节流的传输层通信协议

  • IP(网际协议)

用于封包交换数据网络的协议

TCP/IP协议指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇,

只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以通称为TCP/IP协议族(英语:TCP/IP Protocol Suite,或TCP/IP Protocols)

img

# TCP 协议保证页面文件完整送达浏览器?

  • IP 头是 IP 数据包开头的信息,包含 IP 版本、源 IP 地址、目标 IP 地址、生存时间等信息
  • UDP 头中除了目的端口,还有源端口号等信息
  • IP 负责把数据包送达目的主机
  • UDP 负责把数据包送达具体应用
  • 对于错误的数据包,UDP 不提供重发机制,只是丢弃当前的包,不能保证数据的可靠性,但是传输速度非常块
  • TCP 头除了包含了目标端口和本机端口号外,还提供用于排序的序列号,保证了数据完整传输,连接分为三个阶段:建立连接、传输数据和断开连接

# ✔️ QUIC协议

QUIC(Quick UDP Internet Connections)快速UDP互联网连接 ,基于UDP的传输层协议

降低网络通信的延迟,工作在应用层

可靠性:UDP是不可靠协议,但是QUIC在UDP的基础上做了些改造,使得它提供了和TCP类似的可靠性,提供了数据包重传、拥塞控制、调整传输节奏及其他一些TCP中存在的特性

实现了无需、并发字节流:QUIC的单个数据流可以保证有序交付,但多个数据流之间可能乱序,这意味着单个数据流的传输是按序的,但是多个数据流中接收方收到的顺序可能与 发送方的发送顺序不同

快速握手:QUIC提供0-RTT和1-RTT的连接建立

使用TLS 1.3 传输层安全协议:与更早的TLS版本相比,TLS 1.3有很多优点,最主要原因是 其握手所花费的往返次数更低,能降低协议的延迟

# 特点

  • 0-RTT 建联(首次 建联除外)
  • 类似 TCP的可靠传输
  • 类似 TLS 的加密传输,支持完美前向安全
  • 用户空间的拥塞控制,最新的BBR算法
  • 支持h2的基于流的多路复用,但没有tcp的HOL问题
  • 前向纠错FEC
  • 类似MOTCP的Connection migration

image-20220730203211925

image-20220730203225393

# 无队头阻塞

发送窗口和接收窗口的队头阻塞这两个问题的原因都是TCP 必须按序处理数据, TCP 层为了保证数据有序性,只有在处理完有序的数据后,滑动窗口才能往前滑动,否则就停留

HTTP/2 抽象出 Stream 的概念,实现了 HTTP 并发传输,一个 Stream 代表 HTTP/1.1 里的请求和响应

在 HTTP/2 连接上,不同 Stream 的帧可以乱序发送(因此可以并发不同的 Stream ),因为每个帧头部会携带 Stream ID 信息,接收端可以通过 Stream ID 有序组装成 HTTP 消息,而同一 Stream 内部的帧必须严格有序

但是 HTTP/2 多个 Stream 请求都是在一条 TCP 连接上传输,这意味着多个 Stream 共用同一个 TCP 滑动窗口,当数据丢失,滑动窗口无法往前移动,会阻塞所有的 HTTP 请求,这属于 TCP 层队头阻塞

QUIC 协议也有类似 HTTP/2 Stream 与多路复用的概念,也可以在同一条连接上并发传输多个 Stream,Stream 可认为就是一条 HTTP 请求

QUIC 有自己一套机制保证传输的可靠性。当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响,不存在队头阻塞问题。与 HTTP/2 不同,HTTP/2 只要某个流中的数据包丢失了,其他流会因此受影响

但是 QUIC 给每一个 Stream 都分配了一个独立的滑动窗口,这样使得一个连接上的多个 Stream 之间没有依赖关系,都是相互独立,各自控制的滑动窗口

1650001788270

# 流量控制

QUIC 基于 UDP 传输,而 UDP 没有流量控制,因此 QUIC 实现了自己的流量控制机制。不过,QUIC 的滑动窗口滑动的条件跟 TCP 有差别

# 更快的连接建立

对于 HTTP/1 和 HTTP/2 协议,TCP 和 TLS 是分层的,分别属于内核实现的传输层、openssl 库实现的表示层,因此它们难以合并在一起,需分批次来握手,先 TCP 握手,再 TLS 握手

HTTP/3 在传输数据前需要 QUIC 协议握手,这个握手过程只需要 1 RTT,握手是为确认双方的「连接 ID」,连接迁移基于连接 ID 实现

但 HTTP/3 的 QUIC 协议并不是与 TLS 分层,而是QUIC 内部包含了 TLS,它在自己的帧携带 TLS 里的“记录”,再加上 QUIC 使用 TLS/1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商,下图:

1650001859107

甚至,在第二次连接时,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果

# 连接迁移

基于 TCP 传输协议的 HTTP 协议,通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接,当移动设备的网络从 4G 切换到 WIFI 时, IP 地址变化,就必须断开连接,重新建立连接。建立连接的过程包含 TCP 三次握手和 TLS 四次握手的时延,以及 TCP 慢启动的减速过程,给用户的感觉就是网络突然卡顿了一下,因此连接的迁移成本很高

QUIC 协议没有用四元组的方式“绑定”连接,而是通过连接 ID标记通信的两个端点,客户端和服务器可以各自选择一组 ID 标记自己,即使移动设备的网络变化,导致 IP 地址变化,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”复用原连接,消除重连成本,没有丝毫卡顿感,达到了连接迁移的功能

所以, QUIC 是一个在 UDP 之上的伪 TCP + TLS + HTTP/2 的多路复用的协议

image-20220616161958547

QUIC 是新协议,对于很多网络设备,根本不知道什么是 QUIC,只会当做 UDP,会出现新的问题,因为有的网络设备会丢掉 UDP 包,而 QUIC 基于UDP 实现,如果网络设备无法识别 QUIC 包,就会将其当作 UDP包丢弃

所以,HTTP/3 现在普及的进度非常缓慢,不知道未来 UDP 是否能够逆袭 TCP

# 优点

具有SPDY的所有优点;

0-RTT连接

减少丢包

前向纠错,减少重传时延

自适应拥赛控制,减少重新连接

相当于TLS加密

QUIC主要目标是减少连接延迟,客户端第一次连接服务器时,QUIC只需要1RTT的延迟就可以建立可靠安全的连接,相对于TCP+TLS的1~3次RTT要更加快捷

之后客户端可以在本地缓存加密的认证信息,再次与服务端建立连接时可以实现0RTT的连接建立延迟

QUIC同时复用了HTTP2.0的多路复用(Multiplexing)功能,但由于QUIC基于UDP,避免了HTTP/2的Head-of-Line Bolcking问题

QUIC基于UDP,运行在用户域而不是系统内核,使得QUIC协议可以快速部署和更新

重传与恢复

与TCP类似,QUIC每发送一个包后,都会等待回复一个确认包

当丢包率超过协议的纠错阀值,会显示与隐式进行重传

对于某些重要的数据包,在确认丢失前就会进行重传

这样在网络中会有若干个相同包同时传输,任何一个成功抵达就完成了连接,降低丢包率

接收方对于关键数据包的多次发送和普通数据包的超时重传,都采用相同的重复包处理机制

QUIC在拥塞避免算法上还加入了心跳机包,减少丢包率

QUIC使用FEC(前向纠错)恢复数据,FEC采用简单的异或方式

每次发送一组数据,包含若干个数据包后,并对这些数据包依次做异或运算,最后结果作为一个FEC包再发送出去

接收方收到一组数据后,根据数据包和FEC包即可以进行考验和纠错

安全性

QUIC对每个散装的UDP包都进行了加密和认证的保护,并且避免使用前向依赖(如CBC模式)的方法,这样每个UDP包可以独立地根据IV进行加密或者认证处理

QUIC使用了两级密钥机制:初始密钥和会话密钥。初次连接时不加密,并协商初始密钥

初始密钥协商完毕后再马上协商会话密钥,可以保证密钥的前向安全性,之后通信过程还可以实现密钥的更新

接收方收到密钥更新时,需要用新旧两种密钥对数据进行解密,直到成功才会正式使用新密钥

0RTT握手过程

QUIC握手过程需要一次数据交互,0RTT即可以完成握手过程的密钥协商,比TLS相比效率提供了5倍

初始密钥协商成果后,服务端提供一个临时随机数,双方根据这个随机数生成会话密钥

编辑 (opens new window)
上次更新: 2023/02/07, 15:11:55
Browser
CSS

← Browser CSS→

最近更新
01
青训营真题day01
02-07
02
01day01-html与css
02-07
03
day02-js
02-07
更多文章>
Theme by Vdoing | Copyright © 2022-2023 yuadh | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式