前言
关于学习前端的网络知识,我觉得内容比较杂而且也很多,所以我建议初学者或者备战面试的小伙伴,尝试构建自己的脑图,用脑图帮助构建自己的逻辑图,帮助自己的知识结构自洽
网络模型
OSI 7层模型
| 名称 | 描述 |
|---|---|
| 应用层 | 为操作系统或者网络应用程序提供访问网络服务的接口,协议 HTTP HTTPS SMTP POP3 SSH |
| 表示层 | 把数据转换为接受者能够兼容并且适合传输的内容,比如数据加密,压缩,格式转换等 |
| 会话层 | 负责数据传输中设置和维持网络设备之间的通信连接。管理主机之间的会话进程,还可以利用在数据中插入校验点来实现数据的同步 |
| 传输层 | 把传输表头加至数据形成数据包,完成端到端的数据传输。传输表头包含了协议等信息,比如: TCP,UDP |
| 网络层 | 负责对子网间的数据包进行寻址和路由选择,还可以实现拥塞控制,网际互联等功能。网络层的协议包括:IP,IPX 等。比如路由器就在这 |
| 数据链路层 | 在不可靠的物理介质上提供可靠的传输,主要主要为:物理地址寻址、数据封装成帧、流量控制、数据校验、重发等。比如交换机就在这 |
| 物理层 | 在局域网上传送数据帧,负责电脑通信设备与网络媒体之间的互通,包括针脚,电压,线缆规范,集线器,网卡,主机适配等。 |
TCP/IP 五层协议
| 名称 | 描述 |
|---|---|
| 应用层 | 为操作系统或者网络应用程序提供访问网络服务的接口,协议 HTTP HTTPS SMTP POP3 SSH |
| 传输层 | 它负责为两台主机中的进程提供通信服务 IP,ICMP,RIP,OSPF,BGP,IGMP |
| 网络层 | 它负责为两台主机提供通信服务,并通过选择合适的路由将数据传递到目标主机 TCP,UDP |
| 数据链路层 | 负责将网络层交下来的 IP 数据报封装成帧,并在链路的两个相邻节点间传送帧,每一帧都包含数据和必要的控制信息 |
| 物理层 | 确保数据可以在各种物理媒介上进行传输,为数据的传输提供可靠的环境 SLIP,CSLIP,PPP,ARP,RARP MTU |
HTTP 协议相关
HTTP 是什么
首先要明确这是一个协议,其次是传输的特性,是一个用在计算机世界里的协议,它确立了一种计算机之间的交流通信的规范,以及相关的各种控制和错误处理方式
- 协议
HTTP 是一个用在计算机世界里的协议。它使用计算机能够理解的语言确立了一种计算机之间交流通信的规范,以及相关的各种控制和错误处理方式。
- 传输
- 双向协议
- 允许中间有“中转”或“接力” HTTP 是一个在计算机世界里专门用来在两点之间传输数据的约定和规范
- 超文本 是文字、图片、音频和视频等混合体,关键是含有“超链接”,能够从“超文本”跳到另一个“超文本”,形成复杂的非线性、网状的结构关系
所以,HTTP 是一个在计算机世界里专门用在两点间传输文字、图片、音频、视频等超文本数据的约定和规范
HTTP 发展历史了解吗?目前是发展到哪个版本?
- HTTP/0.9
普通文本协议,确立 HTTP 原型,是 Web 服务的基调
- HTTP/1.0
定位像是一份参考文档,并不具备约束力
增强:
- 增加 HEAD、POST 等方法
- 增加响应状态,标记可能的错误原因
- 引入协议版本号概念
- 引入 HTTP Header 的概念,让 HTTP 处理请求和响应更加灵活
- 传输的数据不再仅限于文本
- HTTP/1.1
经过网景和微软的 “浏览器大战”,HTTP/1.1 发布 RFC 文档。
变更:
- 增加 PUT、DELETE 等新的方法
- 增加缓存管理和控制
- 明确连接管理,允许持久连接
- 允许相应数据分块,利于传输大文件
- 强制要求 Host 头,让互联网主机托管成为可能
- HTTP/2
因为 Google 的 Chrome 广泛使用,使得自家退出的 SPDY 协议成为了新版本 HTTP 协议
HTTP/2 新特点:
- 二进制分帧:二进制协议,不再是纯文本
- 多路复用:可发起多个请求,废弃 1.1 里的管道
- 头部压缩:使用专用算法压缩头部,减少数据传输量
- 服务端推送:允许服务器主动想客户端推送数据
- 增强安全性
- HTTP/3
在 HTTP/2 还在草案时,Google 又发明了 QUIC 协议,而 QUIC 实力过硬,成为 HTTP/3 并进入标准化定制阶段。 HTTP/3 基于 Google 的 QUIC 协议,是未来的发展方向
HTTP 协议的特点
我们将特点分为优点和缺点两种情况
优点:
- 无状态
状态是客户端或服务器里保存的一些数据或标志,记录了通信过程中的一些变化,比如 TCP 协议是有状态的 而 HTTP 每次收发的报文都是互相独立,没有任何的联系 每次之间独立没有相互依赖关系
-
灵活可拓展性
HTTP 协议只规定了报文的基本格式、一些请求方法、版本号、状态码,头字段,并没有严格的语法语义限制body从文本形式到不再仅限于文本形式,而以上的提到的状态码、头字段、请求方法,都是可以让用户自行扩展 -
可靠性传输 因为 HTTP 是基于 TCP/IP 的,而 TCP 本身是可靠的传输协议
-
应用层协议
HTTP 可携带任意头字段和实体数据的报文结构、实现缓存代理以及连接控制等应用
- 请求应答模式
客户端主动发起请求,服务器被动回复请求
缺点:
- 无状态:HTTP 无状态的协议,HTTP服务不会保存关于客户的任何信息
- 明文传输,协议汇总的报文使用文本形式,这就等于说直接暴露给外界,不安全性
- 不安全性,没法保证报文不被篡改
常见的HTTP请求方法
请求方法相当于“动作指令”,表示客户端发出一个“动作指令”,要求服务器端对 URI 定位的资源执行这个动作
目前 HTTP/1.1 规定了 8 种方法,单词都必须是大写的形式:
- GET:获取资源,可以理解为读取或者下载数据
- HEAD:获取资源的元信息
- POST:向资源提交数据,相当于写入或上传数据
- PUT:类似于 POST
- DELETE:删除资源
- CONNECT:建立特殊的连接隧道
- OPTIONS:列出可对资源实行的方法; 要求服务器列出可对资源实行的操作方法,在响应头的 Allow 字段里返回
- TRACE:追踪请求 - 响应的传输路径 多用于对 HTTP 链路的测试或诊断,可以显示出请求 - 响应的传输路径。由于存在漏洞,会泄漏网站信息,所以通常是禁止使用
HTTP 缓存控制工作流程是怎么样的
缓存的工作流程:
- 浏览器发现缓存无数据,于是发送请求,向服务器获取资源
- 服务器响应请求,返回资源,同时标记资源的有效期
- 浏览器缓存资源,等待下次重用
Cache-Control 是对缓存进行控制的
缓存控制使用的头字段是“Cache-Control”,响应报文和请求报文都可以使用
| 范围 | 名称 | 描述 |
|---|---|---|
| 响应报文,请求报文 | no-store | 不允许缓存,用于某些变化非常频繁的页面,如秒杀页面 |
| 响应报文,请求报文 | no-cache | 可以缓存,但在使用之前 要去服务器验证是否过期,是否修改过 |
| 响应报文,请求报文 | max-age=<seconds> | 资源的有效期,单位是秒。在服务器端,时间起算起点是响应报文创建时间,而不是客户端收到报文的时间,也就是包含了链路传输过程花费的时间 |
| 响应报文,请求报文 | no-transform | 缓存不能改变实体主体的媒体类型,可用来防止缓存或代理压缩图片等操作 |
| 响应报文 | public | 可以被任何对象(代理、客户端等)缓存,即使通常不可被缓存的内容(如:POST 请求、该响应没有 max-age 或 Expires 的请求头) |
| 响应报文 | private | 只能被单个用户缓存,不能作为共享缓存(代理服务器不能缓存,用户本地的浏览器可以缓存) |
| 响应报文 | must-revalidate | 代理向源服务器验证即将返回的响应请求是否过期。一旦资源过期(比如已超过 max-age),在成功向源服务器验证之前,缓存都不能用该资源响应后续请求 |
| 响应报文 | proxy-revalidate | must-revalidate 作用相同,但他仅适用于缓存服务器。缓存服务器向源服务器验证返回的响应请求是否过期 |
| 响应报文 | s-maxage=<seconds> | 覆盖 max-age 或者 Expires 头,仅作用域共享缓存(比如代理服务器),私有缓存会被忽略。单位是秒 |
| 请求报文 | max-stale | 表示客户端愿意接受一个已过期的资源。响应不能超过给定的时间。单位是秒 |
| 请求报文 | min-fresh | 表示客户端要求获取一个能在指定的秒数内保持其最新状态的响应。单位是秒 |
| 请求报文 | only-if-cached | 表示客户端只接受 已缓存的响应,并且不会向源服务器检查是否有更新。如果代理没有缓存或者缓存过期,就给客户端返回 504 状态码 |
Keep-alive 的理解
首先我们先理解长链接和短链接的概念。
短链接
在HTTP1.0 版本的时候,短连接(short-lived connections),意思是客户端和服务器的整个连接过程很短暂,不会与服务器保持长时间的连接状态 早期的(HTTP1.0 那时候还不是协议) HTTP 协议被称为“无连接”的协议。
短连接的缺点: TCP 协议里,建立连接和关闭连接都需要多个操作才执行完毕 TCP 建立连接“三次握手”,发送三个数据包,关闭连接“四次挥手”,需要发 4 个数据包,缺点是 浪费性能。
长链接
长连接,也叫“持久连接”(persistent connections)、“连接保活”(keep alive)、“连接复用”(connection reuse)
这种解决办法的思路是“成本均摊”,TCP 连接和关闭非常耗时,那就在一次时间成本内,由原来一个“请求 - 应答”均摊到多个“请求 - 应答”上。所以 Keep-Alive 是为了节省连接的成本,所以才会出现的解决办法。
优点:
- 较少的CPU和内存的使⽤(由于同时打开的连接的减少了);
- 允许请求和应答的HTTP管线化;
- 降低拥塞控制 (TCP连接减少了);
- 减少了后续请求的延迟(⽆需再进⾏握⼿);
- 报告错误⽆需关闭TCP连;
缺点:
- 长时间的 TCP 连接容易导致系统的无效占用,浪费系统资源
长链接相关的内容
HTTP/1.1 的连接默认启用长连接,也可以在请求头里明确要求使用长连接机制,字段是 Connection,值是“keep-alive”
如果服务器支持长连接,它总是会在响应报文放一个“Connection: keep-alive”字段
但是长连接也有缺点。 因为 TCP 连接长时间不关闭,服务器必须在内存里保存它的状态,也就占用了服务器的资源
所以,长连接需要在恰当的时间关闭。 在客户端发送的请求头加上“Connection: close”字段。服务器看到这个字段,就知道客户端要主动关闭连接,于是响应报文也会加上这个字段,然后关闭 TCP 连接
服务器通常不会主动关闭连接,但也可以使用一些策略。如 Nginx,有两种方式:
- 使用“keepalive_timeout”,设置长连接的超时时间,如果在一段时间内连接上没有任何数据收发,就主动断开连接
- 使用“keepalive_requests”,设置长连接上可发送的最大请求次数。比如设置成 1000,那么当 Nginx 在这个连接上处理了 1000 个请求后,主动断开连接
另外,客户端和服务器都可以在报文里附加通用头字段“Keep-Alive: timeout=value”,限定长连接的超时时间。但这个字段的约束力并不强,通信的双方可能并不会遵守,所以不太常见。
HTTP 队头阻塞有了解吗?
由于 HTTP 规定报文必须是“一发一收”,就形成了一个先进先出的“串行”队列,队列只有先后顺序,没有权重,最前面先处理.所以,如果队首因为花费的处理时间太长,后续请求也不得不等待,结果就是其他请求承担了不应有的时间成本 这个发生在 HTTP/1.1 协议中。
HTTP 队头阻塞的解决办法
(1)并发连接:对于一个域名允许分配多个长连接,那么相当于增加了任务队列,不至于一个队伍的任务阻塞其它所有任务。 (2)域名分片:将域名分出很多二级域名,它们都指向同样的一台服务器,能够并发的长连接数变多,解决了队头阻塞的问题。
HTTP/2 的特点
对于 HTTP/2 而言,它对于性能的提升主要在于两点:
- 头部压缩
- 多路复用
- 二进制分帧
当然还有一些颠覆性的功能实现:
- 设置请求优先级
- 服务器推送
HTTP/1.1 和 HTTP/2 之间的差异 (HTTP/2的 特点是什么)
- 兼容 HTTP/1
因为必须要保持功能上的兼容,所以 HTTP/2 把 HTTP 分解成了“语义”和“语法”两个部分,
“语义”层不做改动,与 HTTP/1 完全一致(即 RFC7231)。比如请求方法、URI、状态码、头字段等概念都保留不变
- HTTP 头部差异
针对 HTTP 头部过大,专门制定了一个压缩 HTTP 头部定制的算法,HPack 压缩头部
- 新的二进制格式
在 HTTP/1.1,请求头信息都是文本(ASCII 编码),因为文本会有多一星的字符,不方便计算机的解析,于是 HTTP/2 把报文改为二进制格式,并且统称为 帧
把原来“Headers+Body”拆散为一个个二进制的帧,Headers 帧存放头部字段,Data 帧存放请求实体数据
- 多路复用
流(Stream),是二进制帧的双向传输序列,同一个消息往返的帧会分配一个唯一的流 ID
多路复用,就是用流来在一个 TCP 连接上来进行多个数据帧的通信
在“流”的层面上看,消息(数据包)是一些有序的“帧”序列,而在“连接”的层面上看,消息(数据包)却是乱序收发的“帧”
多个请求 / 响应之间没有了顺序关系,不需要排队等待,也就不会再出现“队头阻塞”问题
二进制帧到达后对方会将 Stream ID 相同的二进制帧组装成完整的请求报文和响应报文
为了更好利用连接,HTTP/2 还添加了一些字段,实现了优先级和流量控制等功能
举例来说,在一个 TCP 连接里面,服务器同时收到了 A 请求和 B 请求,于是先回应 A 请求,结果发现处理过程非常耗时,于是就发送 A 请求已经处理好的部分, 接着回应 B 请求,完成后,再发送 A 请求剩下的部分。
- 服务器推送
在 HTTP/2,服务器不再是完全被动地响应请求,它也能新建 流 来给客户端发送消息。
比如:当 TCP 连接建立后,浏览器请求一个 HTML 文件,而这时候服务器就可以把这个 HTML 文件会引用到 JS、CSS 文件发给客户端,减少客户端的等待
- 强化安全
因为兼容的考虑,HTTP/2 延续了 HTTP/1.1“明文”的特点,可以使用明文传输,不过格式是二进制
而为了区分“加密”和“明文”这两个不同的版本,HTTP/2 协议定义了两个字符串标识符:“h2”表示加密的 HTTP/2,“h2c”表示明文的 HTTP/2,多出的那个字母“c”的意思是“clear text”
HTTP/2 要求通信协议必须是 TLS1.2 以上,还要支持前向安全和 SNI,还禁用了许多弱密码套件
由于 HTTPS 已经是大势所趋,而且主流的浏览器 Chrome、Firefox 等都公开宣布只支持加密的 HTTP/2,所以“事实上”的 HTTP/2 是加密的。也就是说,互联网上通常所能见到的 HTTP/2 都是使用 https 协议名,跑在 TLS 上面
HTTP/2 是如何解决队头阻塞的
在一条TCP链接上可以乱序收发请求和响应,多个请求和响应之间不再有顺序关系, 是在应用层解决这个问题,但实际在底层依然存在
HTTP/2 头部压缩算法是如何实现的
HPACK 算法是专门为压缩 HTTP 头部定制的算法,它是一个“有状态”的算法,需要客户端和服务器各自维护一份“索引表”,也可以说是“字典”(这有点类似 brotli),压缩和解压缩就是查表和更新表的操作
HTTP/2 废除了原有的起始行概念、还废除了版本号和错误原因短语,把起始行里的请求方法、URI、状态码等转换成头字段形式,叫做“伪头字段”(pseudo-header fields)
而 伪头字段 会在名字前加一个“:”表示,比如:“:authority” “:method” “:status”,分别表示的是域名、请求方法和状态码
这样一来,HTTP 报文头就都是“Key-Value”形式,于是 HTTP/2 把床用的头字段定了一个只读的“静态字典表”,所以只要查表就可以知道字段名和对应的值
而自定义字段,则使用“动态字典表”,添加在静态表后面,结构相同,在编码解码时随时更新
比如说,第一次发送请求时的“user-agent”字段长是一百多个字节,用哈夫曼压缩编码发送之后,客户端和服务器都更新自己的动态表,添加一个新的索引号“65”。那么下一次发送的时候就不用再重复发那么多字节了,只要用一个字节发送编号就好
HTTP 和 HTTPS 对比区别
| 类目 | HTTP | HTTPS |
|---|---|---|
| 证书 | 不需要第三方机构出具的证书 | 需要CA证书 |
| 传输形式 | HTTP协议是超文本传输协议,信息是明文传输的 | HTTPS是具有安全性的SSL加密的传输协议 |
| 连接方式 | 无状态连接 | SSL和HTTP协议构建的可进行加密传输、身份认证的网络协议 |
| 端口 | 80 | 443 |
| 安全性 | 低 | 相对较高 |
HTTP 请求头 last-modify 和 e-tag 区别
| 类目 | modify | e-tag |
|---|---|---|
| 格式 | 时间戳 标识 | 字符串 |
| 定义 | 每次服务器文件修改的时候,都会变更 | 针对文件进行简要内容的哈希生成一个唯一的ID |
| 优点 | 对服务器性能影响比较小 | 比对效果很好, |
| 缺点 | 每次修改就算多一个空格,都会改变时间 | 需要损耗一定的性能,每次修改都会重新生成 |
HTTP/3 解决了什么问题
背景
TTP/2 在应用层上解决了“队头阻塞”,而在下层,TCP 协议里,还是会发生 队头阻塞
在网络良好的情况下,包可以很快送达目的地。但如果网络质量比较差,像手机上网的时候,就有可能会丢包。而 TCP 为了保证可靠传输,有个特别的“丢包重传”机制,丢失的包必须要等待重新传输确认,其他的包即使已经收到了,也只能放在缓冲区里,上层的应用拿不出来.
由于这种“队头阻塞”是 TCP 协议固有的,所以 HTTP/2 即使设计出再多的“花样”也无法解决
于是就又发明了一个新的“QUIC”协议,让 HTTP 跑在 QUIC 上而不是 TCP 上
而这个“HTTP over QUIC”就是 HTTP 协议的下一个大版本,HTTP/3
HTTP/2 依然有队头阻塞的问题 在协议层 TCP 上依然存在
QUIC 协议簇
HTTP/3 把下层 TCP 换成了 UDP,而 UDP 是无序的,包之间没有依赖关系,从根本上解决了 队头阻塞
UDP 是一个简单、不可靠的传输协议,不需要建连和端连,通信成本低
QUIC 协议 特点
QUIC 基于 UDP,而 UDP 是无连接 ,所以天生要比 TCP 快
QUIC 基于 UDP 实现了可靠传输,保证数据一定能够抵达目的地。它还引入了类似 HTTP/2 的“流”和“多路复用”,单个“流”是有序的,可能会因为丢包而阻塞,但其他“流”不会受到影响
为了防止网络上的中间设备(Middle Box)识别协议的细节,QUIC 全面采用加密通信,可以很好地抵御窜改和“协议僵化”(ossification)
QUIC 最大的优势是实现了 0-RTT 的建连:
总结 HTTP/3 协议
HTTP/3 把流控制都交给 QUIC 去做。调用的不再是 TLS 的安全接口,也不是 Socket API,而是专门的 QUIC 函数
HTTP/3 里仍然使用流来发送“请求 - 响应”,但它自身不需要像 HTTP/2 那样再去定义流,而是直接使用 QUIC 的流,相当于做了一个“概念映射”
HTTP/3 里的“双向流”可以完全对应到 HTTP/2 的流,而“单向流”在 HTTP/3 里用来实现控制和推送,近似地对应 HTTP/2 的 0 号流
HTTP/3 的帧结构只有两个字段:类型和长度,而且同样都采用变长编码,最小只需要两个字节
HTTP/3 里的帧仍然分成数据帧和控制帧两类,HEADERS 帧和 DATA 帧传输数据,但其他一些帧因为在下层的 QUIC 里有了替代,所以在 HTTP/3 里就都消失了
头部压缩算法在 HTTP/3 里升级成了“QPACK”,使用方式上也做了改变。虽然也分成静态表和动态表,但在流上发送 HEADERS 帧时不能更新字段,只能引用,索引表的更新需要在专门的单向流上发送指令来管理,解决了 HPACK 的“队头阻塞”问题
QPACK 的字典也做了优化,静态表由之前的 61 个增加到了 98 个,而且序号从 0 开始,也就是说“:authority”的编号是 0
HTTP 状态码
状态码类别
| 类别 | 含义 | 例子 | |
|---|---|---|---|
| 1xx | 提示信息 | 表示目前处于协议处理的中间状态,还需要后续的操作 | 101 |
| 2xx | 成功 | 表示报文已经收到并被正确处理 | 200 |
| 3xx | 重定向 | 资源位置发生变化,需要客户端重新发送请求 | 304 |
| 4xx | 客户端错误 | 请求报文有误,服务器无法处理 | 404 |
| 5xx | 服务器错误 | 服务器在处理请求时内部发生了错误 | 504 |
目前 RFC 标准有 40 多种状态码,而状态码的定义是开放的,只要遵守状态码类别的定义,可以自行扩展。
1xx
属于提示信息,表示目前处于协议处理的中间状态,还需要后续的操作
(1) 101 Switching Protocols
意思是 Upgrade 头字段,要求在 HTTP 协议的基础上改成其他的协议继续通信 比如更换为Websocket,如果服务器也同意变更,就会发送状态码 101,但之后的数据传输就不会再使用 HTTP
2xx
表示请求被正常处理了
(1)200 OK
成功状态码,表示客户端发来的请求被服务器端接收到并正常处理了,通常响应报文伴随 body 数据
(2)204 No Content
表示成功,但返回的响应报文没有 body 数据,也不允许返回 body 数据
(3)206 Partial Content
HTTP 分块下载或断点续传的基础,表示客户端发送了“范围请求” 响应报文包含 “Content-Range”指定响应报文 body 数据的具体范围,供客户端确认 例如“Content-Range: bytes 0-99/2000”,意思是此次获取的是总计 2000 个字节的前 100 个字节
3xx ()
表示客户端请求的资源发生了变动,客户端必须用新的 URI 重新发送请求获取资源
(1)301 Moved Permanently
永久性重定向。请求的资源已经分配了新的 URI,以后用新的 URI 访问
(2)302 Found
临时性重定向。请求的资源已被分配了新的 URI,希望本次用新的 URI 访问
301 和 302 都会在响应头里使用 Location 表明后续要跳转的 URI,最终效果相似,浏览器都会重定向到新的 URI,但是语义上有根本的区别,所以用法和场景差距很大
301:比如当前服务做迁移,原来的服务不使用了,所以要配置 301,把所有流量切换到新的服务去
302:比如网站系统需要维护,服务暂时不可用,可以配置 302,把流量临时切换到别的资源去,而浏览器看到 302 时,不会做缓存优化
(3)303 See Other
表示资源存在另一个 URI,应该使用 GET 方法定向获取资源
(4)304 Not Modified
用于 If-Modified-Since 等条件请求,表示资源未修改,用于缓存控制,返回时不包含 body
浏览器缓存分为强制缓存和协商缓存,优先读取强制缓存。
强制缓存分为expires和cache-control,而expires是一个特定的时间,是比较旧的标准和cache-control通常是一个具体的时间长度,比较新,优先级也比较高。
而协商缓存包括etag和last-modified,last-modified的设置标准是资源的上次修改时间, etag是根据资源内容的哈希值 而etag是为了应对资源修改时间可能很频繁的情况出现的,是基于资源的内容计算出来的值,因此优先级也较高。
协商缓存与强制缓存的区别在于强制缓存不需要访问服务器,返回结果是200,协商缓存需要访问服务器,如果命中缓存的话,返回结果是304。
(5)307 Temporary Redirect
临时重定向。和 302 Found 有着相同含义。尽管 302 标准禁止 POST 变换成 GET,但实际上大家并不遵守 而 307 则遵守浏览器标准,不变换方法 原本的用法是用于让post请求的跳转去新的post请求,但也用于hsts跳转。
hsts全称HTTP严格传输安全(HTTP Strict Transport Security,縮寫:HSTS), 功能是要求浏览器下次访问该站点时使用https来访问, 而不再需要先是http再转https。 这样可以避免ssl剥离攻击,即攻击者在用户使用http访问的过程中进行攻击,对服务器冒充自己是用户,在攻击者和服务器中使用https访问,在用户和服务器中使用http访问。
具体使用方法是在服务器响应头中添加 Strict-Transport-Security,可以设置 max-age
ssl 剥离攻击
信任第三方的安全证书,这点被利用于代理软件监听https。
(6)308 Permanently Redirect
永久重定向。和 301 Found 有着相同含义。但是类似 307,不允许重定向后的请求变动
同样是重定向,307,303,302的区别?
302是http1.0的协议状态码,在http1.1协议版本的时候 细化302状态码⼜出来了两个303和307。 303 明确表示客户端应当采⽤get⽅法获取资源,他会把 POST 请求变为GET请求进⾏重定向。 307会遵照浏览器标准,不会从post变为get
4xx (Client Error)
客户端发送的请求报文有误,服务器无法处理,所以客户端是发生错误的原因所在
(1)400 Bad Request
表示报文存在语法错误,笼统的报错,不具体
(2)401 Unauthorized
表示发送的请求需要有通过 HTTP 认证的认证信息 若之前进行过 1 次请求,则认证失败。初次接收 401,会弹出认证窗口
(3)403 Forbidden
表示服务器禁止访问资源,请求被拒绝了
(4)404 Not Found
资源在服务器上未找到。也可以在服务器端拒绝请求且不想说明理由时使用
(5)405 Method Not Allowed
不允许使用某些方法操作资源
(6)406 Not Acceptable
资源无法满足客户端请求的条件
(7)408 Request Timeout
请求超时,服务器等待了过长的时间
(8)409 Conflict
多个请求发生了冲突,可以理解为多线程并发时的竞态
(9)413 Request Entity Too large
请求报文里 body 太大
(10)414 Request-URI Too long
请求行里 URI 过长
(11)429 Too Many Requests
客户端发送了太多的请求,通常是由于服务器的限连策略
(12)431 Request Header Fields Too Large
请求头某个字段或总体太大
5xx (Server Error)
服务器在处理请求时内部发生了错误,无法返回响应数据,属于服务器端的错误码
(1)500 Internal Server Error
与 400 类似,也是通用错误码,表示服务器发生了错误,笼统的报错,不具体
(2)501 Not Implemented
表示客户端请求的功能还不支持
(3)502 Bad Gateway
一般来说,服务器作为网管或者代理时返回的错误码
(4)503 Service Unavailable
表示服务器当前忙(超负荷),暂时无法响应服务 503 是一个临时的状态,服务器不那么忙了以后可以继续提供服务 所以响应报文通常会有“Retry-After”字段,表示客户端可以多久后再次尝试发送请求
HTTPS 协议相关
HTTPS 是什么
在了解是什么之前,先说为什么要有 HTTPS WHAT,WHY,HOW。
什么业务场景用到 HTTPS
由于 HTTP 协议是“明文”的特点,整个传输过程完全透明,任何人都能够在链路中截获、修改、伪造响应/请求报文,数据不具有可信性
比如,购物、网上银行、证券交易,需要安全保护性高的手段应付这些应用场景
再比如,新闻、视频、搜索,如有有恶意用户、恶意代理强行嵌入广告、分流用户这样的流量劫持
什么是 HTTPS
协议名"https",默认端口号 443,语法、语义和 HTTP 完全一样
HTTPS 与 HTTP 最大的区别,它能够鉴别危险的网站,并且尽最大可能保证你的上网安全,防御黑客对信息的窃听、篡改或者“钓鱼”、伪造
其实 HTTPS,特点就在于名字里的“S”,它把 HTTP 下层的传输协议由 TCP/IP 换成了 SSL/TLS,即“HTTP over TCP/IP”变成了“HTTP over SSL/TLS”,
让 HTTP 运行在安全的 SSL/TLS 协议上,不再使用 Socket API,而是调用专门的安全接口 TCP/IP => SSL/TLS
SSL/TLS
SSL,安全套接层(Secure Sockets Layer),处于 OSI 模型中第 5 层(会话层)
TLS,传输层安全(Transport Layer Security)
SSL 发展到 v3 时候,由互联网工程组 IETF 把它改名为 TLS,正式标准化
目前应用最广泛的是 TLS 1.2
TLS 由记录协议、握手协议组成
浏览器和服务器在使用 TLS 建立连接时需要选择一组恰当的加密算法来实现安全通信,这些算法的组合被称为 密码套件(cipher suite,也叫加密套件)
TLS 的密码套件命名非常规范,格式很固定。基本的形式是 “密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法”
TLS/SSL的功能实现主要依赖三类基本算法:散列函数hash、对称加密、非对称加密
加密方法(散列函数hash)
常见的散列函数有MD5、SHA1、SHA256。该函数的特点是单向不可逆,对输入数据非常敏感,输出的长度固定,任何数据的修改都会改变散列函数的结果,可以用于防止信息篡改并验证数据的完整性。 特点: 在信息传输过程中,散列函数不能三都实现信息防篡改,由于传输是明文传输,中间人可以修改信息后重新计算信息的摘要,所以需要对传输的信息和信息摘要进行加密。
对称加密 & 非对称加密
了解 HTTPS 加密过程之前,先要了解清楚对称加密和非对称加密的背后原理和逻辑
对称加密
指加密和解密时使用的密钥都是同一个,是“对称”的 只要保证了密钥的安全,那整个通信过程就可以说具有了机密性。
TLS 常用的对称加密算法有:
- AES
- ChaCha20
非对称加密
对称加密带来了另外一个问题,如何把密码安全地传递给对方,术语叫“密钥交换”
总不能把密钥再加密,那加密再加密,一层套一层,就始终无法解决密钥交换的问题
所以,出现了非对称加密。
非对称加密,有两个密钥,一个叫“公钥”,一个叫“私钥”,两个密钥是不同的,公钥可以公开给任何人使用,而私钥必须严格保密
公钥和私钥有个单向性的特点,虽然都可以用来加密解密,但公钥加密后只能用私钥解密,私钥加密后也只能用公钥解密
这样就解决了密钥交换的问题,网站保管私钥,在网上任意分发公钥,想要登录网站只要用公钥加密就行了,密文只能由私钥持有者才能解密
但是非对称加密有一个缺点就是加密的过程很慢,因此如果每次通信都使用非对称加密的方式的话,反而会造成等待时间过长的问题
数字证书CA是什么?
使用非对称加密里的“私钥”再加上摘要算法,就能够实现“数字签名”,同时实现 身份认证 和 不可否认
数字签名的原理是将之前公钥私钥用法的反过来,也就是私钥加密,公钥解密
私钥加密原文的摘要叫做“签名”
公钥解密,拿到摘要后,再对比原文验证完整性的过程叫做“验签”
只要你和网站互相交换公钥,就可以用“签名”和“验签”来确认消息的真实性,因为私钥保密,黑客不能伪造签名,就能够保证通信双方的身份
HTTPS 流程
HTTPS的通信过程如下:
- 客户端向服务器发起请求,请求中包含使用的协议版本号、生成的一个随机数、以及客户端支持的加密方法。
- 服务器端接收到请求后,确认双方使用的加密方法、并给出服务器的证书、以及一个服务器生成的随机数。
- 客户端确认服务器证书有效后,生成一个新的随机数,并使用数字证书中的公钥,加密这个随机数,然后发给服 务器。并且还会提供一个前面所有内容的 hash 的值,用来供服务器检验。
- 服务器使用自己的私钥,来解密客户端发送过来的随机数。并提供前面所有内容的 hash 值来供客户端检验。
- 客户端和服务器端根据约定的加密方法使用前面的三个随机数,生成对话秘钥,以后的对话过程都使用这个秘钥来加密信息。
HTTPS 优化方式
因为 HTTPS 比 HTTP 增加了一个 TLS 握手,还会花费 2-RTT,除此之外,还有用于生成临时公私钥对、验证证书、加密解密“Pre-Master”的消耗
所以不做优化情况下,HTTPS 可能比 HTTP 慢上几百毫秒甚至几秒
不过现在已经有很多有效的 HTTPS 优化手段,以下用一张图把 TLS 握手过程中影响性能部分标记出来
- 硬件优化
- 选择更快的 CPU,最好内建 AES 优化,这样可以加速握手,也可以加速传输
- 选择“SSL 加速卡”,加密时调用它的 API,让专门的硬件做非对称加密,分担 CPU 的计算压力
- SSL 加速服务器,用专门的服务器集群来彻底“卸载”TLS 握手时的加密解密计算
-
软件优化
-
软件升级
把现在正在使用的软件尽量升级到最新版本,比如把 Linux 内核由 2.x 升级到 4.x,把 Nginx 由 1.6 升级到 1.16,把 OpenSSL 由 1.0.1 升级到 1.1.0/1.1.1
-
协议优化
尽量采用 TLS1.3,它大幅度简化握手过程,完全握手只要 1-RTT,而且更安全即使只能用 1.2,那握手时使用的密钥交换协议应当选用 ECDHE 算法,因为运算快、安全性高,还支持“False Start”。椭圆曲线也选择高性能曲线,最好是 x25519,其次 P-256。对称加密算法,可以选择比“AES_256_GCM”略快一点点的
AES_128_GCM -
-
证书优化
- 证书传输
- 证书验证
服务器的证书可以选择 ECDSA 证书而不是 RSA,因为 224 位 ECC 相当于 2028 位的 RSA,这样带宽和计算量都能降低
由于 CRL 是由 CA 定期发布,所以 CRL 有“时间窗口”安全隐患和累积无用证书的问题,所以证书验证可以使用“OCSP Stapling”(OCSP 装订),可以让服务器预先访问 CA 获取 OCSP 响应,然后再握手时随着证书一起发给客户端,免去了客户端连接 CA 服务器查询的时间
-
会话复用 (会话复用(TLS session resumption),和 HTTP Cache 一样,把“Master Secret”进行缓存“重用”,减少握手和计算成本)
-
Session ID
客户端和服务器首次连接后各自保存一个会话的 ID 号,内存里存储主密钥和其他相关的信息 当客户端再次连接时发一个 ID 过来,服务器就在内存里找,找到就直接用主密钥恢复会话状态,跳过证书验证和密钥交换,只用 1-RTT 就可以建立安全通信
-
Session Ticket
由于服务器必须保存每一个客户端的会话数据,所以千百万级别的网站来说,这样的会话数据存储就成了大问题 于是“Session Ticket”方案出现了,有点类似 HTTP 的 Cookie,存储的责任由服务器转移到客户端,服务器加密会话信息用“New Session Ticket”消息发给客户端,让客户端保存 重连的时候,客户端使用扩展“session_ticket”发送“Ticket”而不是“Session ID”,服务器解密后验证有效期,就可以恢复会话,开始加密通信; 不过“Session Ticket”方案需要使用一个固定的密钥文件(ticket_key)来加密 Ticket,为了防止密钥被破解,保证“前向安全”,密钥文件需要定期轮换,比如设置为一小时或者一天
-
预共享密钥
TLS1.3 利用“Pre-shared Key”(PSK),进一步实现 0-RTT。实现方法是在发送 Session Ticket 的同时带上应用数据(Early Data),不用等到服务端确认 但这样的方式也带来了安全问题,黑客可以截获“PSK”的数据,反复向服务器发送,增加了服务器被攻击的风险 解决办法是只允许使用安全的 GET/HEAD 方法,在消息里假如时间戳、“nonce”验证,或者“一次性票证”限制重放。
-
DNS 相关
DNS 域名解析 是指什么
域名解析是指将域名转换成 IP 地址的过程
DNS 核心系统是一个三层树状、分布式服务,基本对应域名的结构:
- 根域名服务器(Root DNS Server):管理顶级域名服务器,返回“com”“net”“cn”等顶级域名服务器的 IP 地址
- 顶级域名服务器(Top-level DNS Server):管理各自域名下的权威域名服务器,比如 com 顶级域名服务器可以返回 apple.com 域名服务器的 IP 地址
- 权威域名服务器(Authoritative DNS Server):管理自己域名下主机的 IP 地址,比如 apple.com 权威域名服务器返回 www.apple.com 的 IP 地址
DNS 解析过程
域名解析过程: 例如,你要访问“www.apple.com”,就要进行下面的三次查询:
- 访问根域名服务器,它会告诉你“com”顶级域名服务器的地址
- 访问“com”顶级域名服务器,它再告诉你“apple.com”域名服务器的地址
- 最后访问“apple.com”域名服务器,就得到了“www.apple.com”的地址
在 DNS 系统之外,还有两种手段来减轻域名解析的压力,并且能够更快获取结果,基本思路就是“缓存”:
- 缓存
- 网络运营商、大公司建立自己的 DNS 服务器,作为用户 DNS 查询的代理,代理用户访问核心 DNS 系统,这些系统成为“非权威域名服务器”,可以缓存之前的查询结果
- 操作系统对 DNS 解析结果做缓存 (浏览器 DNS 缓存)
- hosts 文件
- 操作系统的“主机映射”文件,在 Linux 里是“/etc/hosts”,在 Windows 里是“C:\WINDOWS\system32\drivers\etc\hosts”,如果操作系统在缓存里找不到 DNS 记录,就会找这个文件
- Nginx 里有一条配置指令“resolver”,它就是用来配置 DNS 服务器的,如果没有它,那么 Nginx 久无法查询域名对应的 IP,也就无法反向代理到外部的网站
DNS 完整解析流程
- 先从浏览器缓存查找
- 再去操作系统缓存中查找
- 接着查找本地 hosts 文件是否有对应的记录
- 到非权威 DNS 服务器中查找是否有这样的缓存记录
- 访问根域名服务器中查找“com”顶级域名服务器的地址
- 访问顶级域名服务器查询“不存在.com”,找不到,抛出错误,逐级返回,告诉用户无法找到这个域名对应的 IP 地址
- 假设 5 找到了,继续去二级域名服务器查找,根据“www.不存在.com”找到权威 DNS 服务器地址
- 然后访问权威 DNS 服务器找到“www.不存在.com”找到对应的 IP 地址
- 然后逐级返回并更新操作系统缓存、浏览器缓存
DNS 迭代查询和递归查询
顾名思义,迭代就是多次进行的,递归只需要进行一次,然后最终返回,同样DNS解析是包含两种查询的过程
- 递归查询指的是查询请求发出后,域名服务器代为向下一级域名服务器发出请求,最后向用户返回查询的最终结果。使用递归 查询,用户只需要发出一次查询请求。
- 迭代查询指的是查询请求后,域名服务器返回单次查询的结果。下一级的查询由用户自己请求。使用迭代查询,用户需要发出 多次的查询请求.
DNS 记录和报文
DNS 服务器中以资源记录的形式存储信息,每一个 DNS 响应报文一般包含多条资源记录。一条资源记录的具体的格式为
(Name,Value,Type,TTL)
复制代码其中 TTL 是资源记录的生存时间,它定义了资源记录能够被其他的 DNS 服务器缓存多长时间。 常用的一共有四种 Type 的值,分别是 A、NS、CNAME 和 MX ,不同 Type 的值,对应资源记录代表的意义不同:
- 如果 Type = A,则 Name 是主机名,Value 是主机名对应的 IP 地址。因此一条记录为 A 的资源记录,提供了标 准的主机名到 IP 地址的映射。
- 如果 Type = NS,则 Name 是个域名,Value 是负责该域名的 DNS 服务器的主机名。这个记录主要用于 DNS 链式 查询时,返回下一级需要查询的 DNS 服务器的信息。
- 如果 Type = CNAME,则 Name 为别名,Value 为该主机的规范主机名。该条记录用于向查询的主机返回一个主机名 对应的规范主机名,从而告诉查询主机去查询这个主机名的 IP 地址。主机别名主要是为了通过给一些复杂的主机名提供 一个便于记忆的简单的别名。
- 如果 Type = MX,则 Name 为一个邮件服务器的别名,Value 为邮件服务器的规范主机名。它的作用和 CNAME 是一 样的,都是为了解决规范主机名不利于记忆的缺点。
TCP & UDP 相关
TCP 和 UDP都是传输层协议,他们都属于TCP/IP协议族:
UDP 定义
用户数据协议(User Datagram Protocol),是无连接的,尽最大可能交付(即不可靠),没有拥塞控制(不提供复杂的控制机制),面向报文(对于应用层的报文不合并也不拆分,只添加 UDP 头部),支持多种传输方式(一对一、一对多、多对一、多对多)的通信。
UDP 首部格式
首部字段只有 8 个字节,包括源端口、目的端口、长度、检验和。 12 字节的伪首部是为了计算检验和临时添加的。
TCP 定义
传输控制协议(Transmission Control Protocol),是面向连接的、可靠的、基于字节流的传输层通信协议。 而且有流量控制,拥塞控制,提供全双工通信,每一条 TCP 连接只能是点对点的(一对一)。
特点
- 面向连接
- 指客户端和服务器的连接,在双方通信之前,TCP 需要三次握手建立连接。
- 可靠性
- 可靠有序,不丢不重。
- TCP 为了保证传输的可靠性给每一个包一个序号,同时也保证了传输到接收方的包是按序排列。接收方对于已经接受的包会回传一个相应的确认(ACK),如果发送方在确认的往返时延(RTT)没有收到确认,就会重新发送
- 基于字节流
- TCP 不像 UDP 一个一个报文传输,而是在不保存报文边界的情况下以字节流的形式传输。
TCP 首部格式
UDP 和 TCP 对比
| UDP | TCP | |
|---|---|---|
| 是否连接 | 无连接 | 面向连接 |
| 传输可靠性 | 不可靠性传输,不使用控制流量和拥塞控制 | 可靠性传输,使用流量控制和拥塞控制 |
| 连接对象个数 | 支持一对一,一对多,多对一,多对多方式通信 | 1vs1 一对一连接 |
| 传输方式 | 无连接 | 面向字节流 |
| 首部的开销大小 | 开销小,仅8字节 | 首部最小20字节,最大60字节 |
| 适用场景 | 实时应用 | 可靠性传输,文件传输 |
TCP 三次握手 & 过程
所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送 3 个包。
三次握手的目的是连接服务器指定端口,建立 TCP 连接, 并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。
在 socket 编程中,客户端执行 connect() 时。将触发三次握手。
从最开始双方都处于CLOSED状态。然后服务端开始监听某个端口,进入了LISTEN状态。
- 第一次握手(SYN=1,seq=x) 客户端发送一个 TCP 的 SYN=1 的包,随机产生初始序号 seq=x 到服务器,请求连接, 客户端进入SYN-SENT状态。
- 第二次握手(SYN=1,ACK=1,seq=y,ack=x+1) 服务器收到数据包,并将 SYN=1、ACK=1(对应客户端发来的 SYN)、ack(Ack Number)设置为客户端的 ISN+1 即 ack=x+1、随机产生序号 seq=y 的数据包发给客户端以示确认连接请求, 服务器进入SYN_RCVD状态
- 第三次握手(ACK=1,seq=x+1,ack=y+1) 客户端收到确认,再次发送确认包,SYN 标志为 0,ACK=1、seq=x+1、ack=y+1, 客户端发送完成后,客户端进入ESTABLISHED状态。
- 服务器收到第三次握手的 ACK 之后,也进入ESTABLISHED状态,随后客户端和服务器之间开始传输数据。
TCP 四次挥手 & 过程
客户端或服务器均可主动发起挥手动作,在 socket 编程中,任何一方执行 close() 操作即可产生挥手操作。
过程解析
- 第一次挥手(FIN=1,seq=u) 客户端发送连接释放报文,并停止发送数据,主动关闭TCP连接。 发送完毕后,客户端进入FIN_WAIT_1状态。
- 第二次挥手(ACK=1,ack=u+1,seq=v) 服务器端回送一个确认报文,客户到服务器的这个方向的连接就释放了,进入半关闭状态。 发送完毕后,服务器端进入CLOSE_WAIT状态,客户端接收到这个确认包之后,进入FIN_WAIT_2状态,等待服务器端关闭连接。
- 第三次挥手(FIN=1,ACK=1,seq=w,ack=u+1) 服务器端发完数据,就发出连接释放报文,主动关闭TCP连接。 发送完毕后,如服务器端进入LAST_ACK状态,等待来自客户端的最后一个ACK。
- 第四次挥手(ACK=1,seq=u+1,ack=w+1) 客户端回送一个确认报文,并进入TIME_WAIT状态,等到时间等待计算器设置的2MSL(最长报文寿命)后,连接彻底关闭,进入CLOSED状态。
服务器端接收到确认报文之后,关闭连接,进入CLOSED状态。
TCP 如何控制拥塞的
如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度很高。
因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。
流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。
拥塞控制,TCP 每条连接都需要维护两个核心状态:
- 拥塞窗口(Congestion Window,cwnd)
- 慢启动阈值(Slow Start Threshold,ssthresh)
涉及算法
- 慢开始
- 拥塞避免
- 快重传
- 快恢复
拥塞窗口
指目前自己还能传输的数据量大小。
限制的是:发送窗口的大小。
拥塞窗口(cwnd)是状态变量,与发送方窗口的区别是,实际决定发送方能发送多少数据是发送方窗口。
慢开始
拥塞控制首先采用一种保守的算法来慢慢适应整个网路,这种算法叫做 慢启动。
运作过程:
- 握手,宣告自己的接收窗口大小
- 双方初始化自己的拥塞窗口大小
- 发送端每收到一个 ACK,拥塞窗口大小 + 1,也就是每一个 RIT,cwnd 翻倍。如果初始窗口是 10,那么每一轮10个报文传完发送端收到 ACK
如果出现超时,则令 ssthresh = cwnd / 2,然后重新执行慢开始。
拥塞避免
当 cwnd >= ssthresh(慢开始阈值)时,进入拥塞避免。
每个轮次只将 cwnd 加 1。
慢启动和拥塞避免是一起作用的。
快重传
TCP 传输过程中,如果发生了丢包,即接收端发现数据段不是按序到达的时候,接收端的处理是重复发送之前的 ACK。
比如第 5 个包丢了,即使第 6、7 个包到达的接收端, 接收端也一律返回第 4 个包的 ACK。 当发送端收到 3 个重复的 ACK 时,意识到丢包了,于是马上进行重传,不用等到一个 RTO 的时间到了才重传。
快恢复
发送端收到三次重复 ACK 之后,发现丢包,觉得现在的网络已经有些拥塞了,自己会进入快速恢复阶段。
发送端作出如下变化:
- ssthresh = cwnd / 2
- cwnd = ssthresh
也就是说,快恢复阶段,直接进入拥塞避免,cnwd 线性增加。
TCP 可靠传输机制是如何实现的
主要通过以下方式实现可靠性:
- 面向字节流和缓存机制
- 超时重传和确认机制 TCP 的发送方在规定的时间内没有收到确认就要重传已发送的报文段(超时重传)。重传时间是动态改变的,依据的是 RTTS(加权平均往返时间)。
- 检验和机制 保持首部和数据的检验和。如果发生查错,TCP 则将丢弃这个数报文和不确认收到此报文。
- 字节编号机制 TCP 报文根据数据包传输,而数据包可能会失序,因此 TCP 报文也可能会失序。所以 TCP 能根据序号进行排序,保证数据是有序传入应用层。
- 自动丢弃重复机制 数据包会发生重复,TCP 的接收端必须丢弃重复的数据
- 流量控制 TCP 连接的每一方都有固定大小的缓冲空间。TCP 的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。
TCP 粘包是指什么,能解释一下吗,如何处理
首先我们先了解一下下面两个算法 Nagle算法(延迟传送算法) 确认任意时刻,只能有一个未确认的小段, 包累计到一定程度才会发送过去,在数据发送之前缓存起来,短时间多个数据就会一起发送,目的是为了减少IO的损耗
Cork算法(计算包大小然后发送的算法) 当包的大小到达一定值以后一并发送过去
但是如果是多条消息, 或者是别的⽤途的数据那么就需要处理粘包.
顾明思议,就是数据包之间产生了粘合,打个比方,有数据包A,B需要发送到客户端,客户端先接受到了数据包A的部分数据,然后接受剩下的数据包A的数据 + 数据包B,出现这种情况的话就是粘包了
如何解决粘包的问题
- 多次发送之前间隔⼀个等待时间
- 适用场景是低频率交互低的场景,缺点是传输效率很低
- 关闭 Nagle算法
- 适用场景交互场景比较低的场景,每次发送之前直接不缓存直接发送过去,所以数据包都会比较大,适合传输文件,同样因为文件变大了网络差的情况下,很容易就会出现丢包的情况,导致需要重新传输
- 进行封包/拆包
- 数据包在发送之前, 在其前/后放⼀些有特征的数据, 然后收到数据的时 候根据特征数据分割出来各个数据包,学习过 NodeJS 上传大文件的时候,就是拆包再组装的原理相同(大部分情况用这个)
TCP 如何控制流量的,流量控制机制是怎么样的
TCP采用大小可以变更的滑动窗口进行流量控制的,窗口大小的单位是字节。这里窗口大小是指每次传输的数据大小
滑动窗口
滑动窗口协议在在发送方和接收方之间各自维持一个滑动窗口,发送方是发送窗口,接收方是接收窗口,而且这个窗口是随着时间变化可以向前滑动的。 它允许发送方发送多个分组而不需等待确认。TCP的滑动窗口是以字节为单位的。
Websocket
定义
HTML5开始提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。
特点:
- 对大部分web开发者来说,上面这段描述有点枯燥,其实只要记住几点:
- WebSocket可以在浏览器里使用
- 支持双向通信
实例代码
看看 HTTP 状态情况
GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
服务器端
var app = require('express')();
var server = require('http').Server(app);
var WebSocket = require('ws');
var wss = new WebSocket.Server({ port: 8090 });
wss.on('connection', function connection(ws) {
console.log('server: receive connection.');
ws.on('message', function incoming(message) {
console.log('server: received: %s', message);
});
ws.send('world');
});
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
app.listen(3000);
客户端
var ws = new WebSocket('ws://localhost:8090');
ws.onopen = function () {
console.log('ws onopen');
ws.send('from client: hello');
};
ws.onmessage = function (e) {
console.log('ws onmessage');
console.log('from server: ' + e.data);
};
数据如何进行传递的
- 第一条消息
FIN=1, 表示是当前消息的最后一个数据帧。服务端收到当前数据帧后,可以处理消息。opcode=0x1,表示客户端发送的是文本类型。
- 第二条消息
FIN=0,opcode=0x1,表示发送的是文本类型,且消息还没发送完成,还有后续的数据帧。 FIN=0,opcode=0x0,表示消息还没发送完成,还有后续的数据帧,当前的数据帧需要接在上一条数据帧之后。 FIN=1,opcode=0x0,表示消息已经发送完成,没有后续的数据帧,当前的数据帧需要接在上一条数据帧之后。服务端可以将关联的数据帧组装成完整的消息。
Client: FIN=1, opcode=0x1, msg="hello"
Server: (process complete message immediately) Hi.
Client: FIN=0, opcode=0x1, msg="and a"
Server: (listening, new message containing text started)
Client: FIN=0, opcode=0x0, msg="happy new"
Server: (listening, payload concatenated to previous message)
Client: FIN=1, opcode=0x0, msg="year!"
Server: (process complete message) Happy new year to you too!
数据掩码的作用
WebSocket协议中,数据掩码的作用是增强协议的安全性。但数据掩码并不是为了保护数据本身,因为算法本身是公开的,运算也不复杂。除了加密通道本身,似乎没有太多有效的保护通信安全的办法。
那么为什么还要引入掩码计算呢,除了增加计算机器的运算量外似乎并没有太多的收益(这也是不少同学疑惑的点)。
答案还是两个字:安全。但并不是为了防止数据泄密,而是为了防止早期版本的协议中存在的代理缓存污染攻击(proxy cache poisoning attacks)等问题。