update: content update

This commit is contained in:
Unix_Kernel
2024-11-13 14:47:32 +08:00
parent dae10db9d4
commit aca020701b
14 changed files with 285 additions and 78 deletions

View File

@@ -2,7 +2,7 @@
## TCP/UDP
TCP 传输的核心公式:速度 = 窗口大小/往返时间,这个公式对于理解传输本质和排查传输问题具有很强的知道意义。
TCP 传输的核心公式:速度 = 窗口大小/往返时间,这个公式对于理解传输本质和排查传输问题具有很强的指导意义。
TCP 里面有三种窗口发送窗口、接收窗口、拥塞窗口。如果没有特别说明TCP Window 指的是接收窗口。
@@ -18,7 +18,7 @@ TCP 传输的起始阶段,速度都是从低到高升上来的,很少一上
这个机制其实就是 TCP 的拥塞控制。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TCPWindowDiff.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TCPWindowDiff.png)
@@ -32,7 +32,7 @@ TCP 使用拥塞机制来确保传输速度和稳定性。拥塞机制是通信
Slow start即 TCP 传输的开始阶段是从一个相对低的速度开始的。之后拥塞窗口会翻倍方式增长。每次 TCP 收到一个确认了数据的 ACK拥塞窗口就增加1个 MSS
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TCP-SlowStart.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TCP-SlowStart.png)
当收到重复的 ACK 报文即确认号一样比如收到2个 ACK但他们的确认号一样那么第二个 ACK 就不算是“确认数据的 ACK”拥塞窗口就不会增加2个 MSS只会增加1个 MSS。
@@ -52,11 +52,11 @@ Slow start即 TCP 传输的开始阶段是从一个相对低的速度开始
**慢启动阈值** ssthresh过了这个阈值拥塞窗口的增长速度就立刻变慢了变为每过一个 RTT拥塞窗口就增加一个 MSS之前是没收到一个确认数据的 ACK 就增加1个 MSS
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TCP-SlowStartChart.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TCP-SlowStartChart.png)
上图所示,假设 ICW 是4个 MSSssthresh 是32个 MSS慢启动阶段经过1个 RTT 后CW 扩大为8MSS、16MSS、32MSS。等到了阈值之后TCP就进入拥塞避免阶段了。每过一个 RTT拥塞窗口只增加1MSS曲线就变为较为斜率较低的直线了。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TCP-CongestionAvoidance.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TCP-CongestionAvoidance.png)
QA如果拥塞窗口大小正好等于慢启动阈值那么发送方这时候是需要采用拥塞避免过程线性增长还是继续选择慢启动过程指数增长[RFC5681](https://datatracker.ietf.org/doc/html/rfc5681) 规定是说两者都可以。
@@ -89,7 +89,7 @@ Congestion Window拥塞窗口简写 CW。拥塞窗口是针对每个连接
TCP 野蛮生长后当达到慢启动阈值之后会进入拥塞避免阶段。这个阶段的特点是“和性增长乘性降低”Addictive increase/multiplicative decreaseAIMD解释下就是拥塞避免阶段每个RTT时间拥塞窗口只增长1MSS这个阶段的拥塞窗口增长是线性的斜率比较低的直线当探测到拥塞时拥塞窗口就要往下降下降是直接减半的叫做乘性降低。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TCP-CongestionAvoidanceProgress.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TCP-CongestionAvoidanceProgress.png)
@@ -115,7 +115,7 @@ TCP 会利用另一种机制来解决超时重传带来的时间等待问题,
快速恢复是 TCP Reno 算法引入的一个阶段,是和“快速重传”搭配工作的。跟之前的“慢启动-拥塞避免-慢启动-拥塞避免”不同的是,当遇到拥塞点之后,通过快速重传,就不再进入慢启动了,而是从这个减半的拥塞窗口开始,保持跟拥塞避免一样的线性增长,直到遇到下一个拥塞点。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TCP-QuickRecover.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TCP-QuickRecover.png)
@@ -280,7 +280,7 @@ Cache-Control 中比较常用的就是 max-age此外还有几个
将网页点击前进、后退会发现“ Status Code200 from disk cache”
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/CacheControlFromDisk.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/CacheControlFromDisk.png)
### 条件请求
@@ -290,7 +290,7 @@ Cache-Control 中比较常用的就是 max-age此外还有几个
条件请求共5个头字段常用的是 `If-Modified-Since` + `Last-modified``If-None-Match` + `ETag`这两个(需要搭配使用)。需要在第一次响应报文预先提供 `Last-modified``ETag`,然后第二次请求时就可以带上缓存里的原值,验证资源是否是最新的。如果服务端资源没有更新,则返回 “304 Not Modified”表示缓存有效 浏览器只需要更新缓存日期便可继续使用本地缓存
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/CacheComunicate.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/CacheComunicate.png)
Last Modified 代表资源的最后修改时间
@@ -401,7 +401,7 @@ HTTP 传输链路上,不只是客户端有缓存,服务器上的缓存也是
### 客户端的缓存控制
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/ClientCacheControl.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/ClientCacheControl.png)
- max-stale如果代理上的缓存过期了也可以接受但不能过期太多超过 x 秒也会不要
@@ -593,7 +593,7 @@ HTTPS 其实是一个“非常简单”的协议RFC 只有短短的 7 页
HTTPS 的核心在于 `s` ,也就是把 HTTP 下层传输协议由 TCP/IP 换为了 SSL/TLS从 "HTTP Over TCP/IP" 变为 "HTTP Over SSL/TLS"。让 HTTP 运行在了安全的 SSL/TLS 协议上,收发报文不再使用 Socket API而是调用专门的安全接口。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTPSOverSSL.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTPSOverSSL.png)
SSL(Secure Sockets Layer),安全套接字层,在 OSI 模型中第五层会话层由网景公司在1994年发明有 V2、V3 版本V1 因为有严重缺陷从未公开过。SSL 发展到 V3 被证明是一个非常好的安全通信协议,于是互联网工程组 IEFT 在1999年更名为 TLS(Transport Layer Security)传输层安全正式标准化版本号从1.0计数,所以 TLS1.0 也就是 SSL V3.1/
@@ -695,7 +695,7 @@ SHA-2 其实是一系列摘要算法的统称包含6中常用的是 SHA224
知道问题症结所在,也比较好解,真正的完整性必须建立在“机密性”基础上。使用混合加密系统中用会话密钥加密消息和摘要,这样中间人无法得知明文。这个过程叫做“哈希消息认证码”(HMAC)
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTPSIntegrity.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTPSIntegrity.png)
#### 数字签名
@@ -707,7 +707,7 @@ SHA-2 其实是一系列摘要算法的统称包含6中常用的是 SHA224
非对称加密效率太低,所以私钥只加密原报文的摘要,这样运算量小,速度也快。得到的数字签名也很小,方便传输和保管。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTPSSign.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTPSSign.png)
这个过程被叫做“签名”、“验签”。
@@ -725,7 +725,7 @@ CA 如何自证?
信任链。小一点的 CA 可以让大 CA 签名认证,但链条的最后,也就是 Root CA就只能自己证明自己了这个就叫“自签名证书”Self-Signed Certificate或者“根证书”Root Certificate。你必须相信否则整个证书信任链就走不下去了。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTPSCAChain.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTPSCAChain.png)
浏览器内置各大 CA 的根证书上网的时候只要服务器发过来它的证书就可以验证证书里的签名顺着证书链Certificate Chain一层层地验证直到找到根证书就能够确定证书是可信的从而里面的公钥也是可信的。
@@ -759,7 +759,7 @@ TLS 包含多个子协议,每个协议都有各自的职责,比较常用的
关于记录可以用下图解释
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TLSRecords.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TLSRecords.png)
可以看出:
@@ -773,19 +773,19 @@ TLS 包含多个子协议,每个协议都有各自的职责,比较常用的
下图是 TLS 完整的流程
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TLSFullPipeline.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TLSFullPipeline.png)
上 Demo以 Mac 上 wireshark 抓取 `https://github.com` 为例。
第一步:在 TCP 3次握手建立连接后客户端发送一个 “Client Hello“ 的消息,表示开始和服务器沟通。包含客户端的 TLS 版本号、支持的密码套件、随机数,这些信息用于后续生成会话密钥。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TLSHandShake1.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TLSHandShake1.png)
其实,这些信息的作用都是**协商**,客户端告诉浏览器我这边的 TLS 协议是什么版本,我本地支持的加密套件都有哪些,你后续从我支持的列表中选一个。
第二步:服务端收到 “Client Hello” 的消息后,会返回一个 “Server Hello” 的消息。核对版本号,同时也会生成一个随机数,然后从客户端的加密套件中选择一个作为本次通信使用的密码套件。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TLSHandShake2.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TLSHandShake2.png)
可以看到此时,服务端选择了 `Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)`这个加密套件。服务端返回给客户端的这些信息也就代表“TLS 版本号对上了,你这边给的加密套件很多,我选了一个最合适的,椭圆曲线 + RSA + AES + SHA384。另外我给了你一个随机数你需要保存后续使用”
@@ -799,13 +799,13 @@ TLS 是建立在 TCP 的上层协议,因此要先按照 TCP 的规则来,也
同时服务器选择了 ECDHE 算法所以在发送了服务器证书后马上发送“Server Key Exchange”消息。里面是椭圆曲线的公钥(Server Params),用来实现密钥的交换算法,再加上自己的私钥签名认证(用私钥对椭圆曲线的 public key 做了签名认证生成了 Signature)
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TLSHandShake3.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TLSHandShake3.png)
意味着,服务器告诉客户端,我这边选择的加密套件有点复杂,所以再给你一个算法的参数,和随机数一样,先保存后续使用。为了保证我就是我,我给参数 public key 做了签名。
第四步服务端发送“Server Hello Done”消息。告诉客户端我的基础信息就是这些打招呼阶段结束
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TLSHandShake4.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TLSHandShake4.png)
至此,第一个消息往返就结束了(2个TCP包),客户端和服务端通过**明文**共享了Client Random、Server Random、Server Params。
@@ -813,7 +813,7 @@ TLS 是建立在 TCP 的上层协议,因此要先按照 TCP 的规则来,也
第五步:客户端按照加密套件的要求,也生成了一个椭圆曲线的公钥(Client Params)用“Client Key Exchange”消息发送给服务器
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TLSHandShake5.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TLSHandShake5.png)
至此客户端和服务器都拿到了密钥交换算法的2个参数(Client Params、Server Params),然后用 ECDHE 算法计算出一个随机数叫“Pre-Master”也叫做“预主密钥”。
@@ -842,7 +842,7 @@ master_secret = PRF(pre_master_secret, "master secret",
第六步服务器发送“Change Cipher Spec” 和 “Encrypted Handshake Message” 消息,双方都解密 OK握手正式结束。后续请求就收发被加密的 HTTP 数据了。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TLSHandShake6.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TLSHandShake6.png)
#### RSA 握手
@@ -926,7 +926,7 @@ HTTPS 建立连接时除了要做 TCP 握手,还要做 TLS 握手,在 1.2
做法:利用了扩展。客户端在 “Client Hello” 消息里直接用 “supported_groups” 带上支持的曲线,比如 P-256、x25519用“key_share”带上曲线对应的客户端公钥参数用 “signature_algorithms” 带上签名算法。服务器收到后在这些扩展里选定一个曲线和参数,再用 “key_share” 扩展返回服务器这边的公钥参数,就实现了双方的密钥交换,后面的流程就和 1.2 基本一样了。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TLS1.3Pipeline.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TLS1.3Pipeline.png)
### HTTPS 加速
@@ -946,7 +946,7 @@ HTTPS 连接大致上可以划分为两个部分:建立连接时的非对称
下图是存在改进空间的地方。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TLSSpeedDisadvantage.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TLSSpeedDisadvantage.png)
#### 硬件优化
@@ -1006,7 +1006,7 @@ Session Ticket 方案需要使用一个固定密钥文件(ticket_key)来加密 T
`False Start``Session ID``Session Ticket`等方式只能实现 1-RTT而 TLS1.3 更进一步实现了 0-RTT原理和 `Session Ticket` 差不多,但在发送 Ticket 的同时会带上应用数据(Early Data),免去了 1.2 里的服务器确认步骤,这种方式叫 `Pre-shared Key`简称为“PSK”。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/TLS1.3PSK.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/TLS1.3PSK.png)
PSK 存在缺点,为了追求效率而降低一些安全性,容易收到“重放攻击”,黑客截获 PSK 后,原封不动的向服务器发出去。解决办法是只允许安全的 HTTP 请求方法,如 HEAD/GET在消息中增加时间戳、nonce 验证。
@@ -1040,7 +1040,7 @@ PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n
但在 wireshark 抓包中HTTP/2 连接前言被称为 “Magic“。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTP2ConnectionPreface.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTP2ConnectionPreface.png)
### 头部压缩
@@ -1054,13 +1054,13 @@ HTTP/1 使用头部字段“Content-Encoding” 指定 Body 的编码方式,
现在 HTTP 报文头就简单了,全都是 `Key-Value` 形式的字段,于是 HTTP/2 就为一些最常用的头字段定义了一个只读的“静态表”Static Table
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTP2StaticTable.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTP2StaticTable.png)
完整的静态表可以查看[RFC 7541 - HPACK: Header Compression for HTTP/2](https://httpwg.org/specs/rfc7541.html#static.table.definition)
假设使用了自定义字段怎么办?动态表(Dynamic Table) 添加在静态表后面,结构相同,在编码的时候随时更新。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTP2DymaicTable.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTP2DymaicTable.png)
在 HTTP/2 连接上发送的报文越来越多,客户端、服务器的“字典”也会越来越丰富,最终每次的头部字段都会变成一两个字节的代码,原来上千字节的头用几十个字节就可以表示了,压缩效果比 gzip 要好得多。
@@ -1074,11 +1074,11 @@ HTTP/2 以前采用纯文本格式的报文(ASCII 码),但 HTTP/2 向 TCP/IP
这种策略有点像 `Chunked` 分块编码的方式,化整为零,但 HTTP/2 数据分帧后 “Header + Body” 的报文结构就没了,协议看到的是一个个碎片。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTP2BinaryData.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTP2BinaryData.png)
HTTP/2 的帧结构有点类似 TCP 的段或者 TLS 里的记录,但报头很小,只有 9 字节,非常地节省(可以对比一下 TCP 头,它最少是 20 个字节)。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTP2BinaryFrameStructure.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTP2BinaryFrameStructure.png)
帧开头是 3 个字节的长度(但不包括头的 9 个字节),默认上限是 2^14最大是 2^24也就是说 HTTP/2 的帧通常不超过 16K最大是 16M。
@@ -1098,7 +1098,7 @@ HTTP/2 总共定义了 10 种类型的帧,但一个字节可以表示最多 25
从“流”的层面上看,消息是一些有序的“帧”序列,而在“连接”的层面上看,消息却是乱序收发的“帧”。多个请求 / 响应之间没有了顺序关系,不需要排队等待,也就不会再出现“队头阻塞”问题,降低了延迟,大幅度提高了连接的利用率。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTP2Stram.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTP2Stram.png)
HTTP/1 中请求-响应报文来回一次是一次 HTTP 通信HTTP/2中一个流也做了类似的事情。
@@ -1120,7 +1120,7 @@ HTTP/2流的特点
- 第 0 号流比较特殊,不能关闭,也不能发送数据帧,只能发送控制帧,用于流量控制
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTP2StreamExample.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTP2StreamExample.png)
可以看到:
@@ -1132,7 +1132,7 @@ HTTP/2流的特点
### 流状态转换
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTP2StatusChange.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTP2StatusChange.png)
上图对应到标准的 HTTP 请求应答。
@@ -1170,7 +1170,7 @@ HTTP/2 还在一定程度上改变了传统的“请求 - 应答”工作模式
HTTP/2 是建立在 HPack + Stream + TLS1.2 之上的。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTP2ProtocolStack.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTP2ProtocolStack.png)
QA明文形式的 HTTP/2h2c有什么好处应该如何使用呢
@@ -1236,7 +1236,7 @@ HTTP Over QUIC 就是 HTTP3完美解决队头阻塞问题。
### QUIC 协议
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTP3Protocol.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTP3Protocol.png)
可以看到 HTTP3 对比 HTTP2 将 TCP 换为 UDP因为 UDP 无序,包之间没有依赖关系,所以从根本上解决了“队头阻塞”问题
@@ -1260,7 +1260,7 @@ QUIC 的基本数据传输单位是包packet和帧frame一个包
QUIC 使用不透明的 “**连接 ID**” 来标记通信的两个端点,客户端和服务器可以自行选择一组 ID 来标记自己,这样就解除了 TCP 里连接对“IP 地址 + 端口”即常说的四元组的强绑定支持“连接迁移”Connection Migration
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/QUICPacket.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/QUICPacket.png)
比如从外面玩回到家,手机会自动由 4G 切换到 WiFi。这时 IP 地址会发生变化TCP 就必须重新建立连接。而 QUIC 连接里的两端连接 ID 不会变,所以连接在“逻辑上”没有中断,它就可以在新的 IP 地址上继续使用之前的连接,消除重连的成本,实现连接的无缝迁移。
@@ -1268,7 +1268,7 @@ QUIC 的帧里有多种类型PING、ACK 等帧用于管理连接,而 STREAM
QUIC 里的流与 HTTP/2 的流非常相似,也是帧的序列。但 HTTP/2 里的流都是双向的,而 QUIC 则分为双向流和单向流。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/QUICStream.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/QUICStream.png)
QUIC 帧普遍采用变长编码,最少只要 1 个字节,最多有 8 个字节。流 ID 的最大可用位数是 62数量上比 HTTP/2 的 2^31 大大增加。
@@ -1282,7 +1282,7 @@ HTTP/3 里仍然使用流来发送“请求 - 响应”,但它自身不需要
HTTP/3 里的“双向流”可以完全对应到 HTTP/2 的流,而“单向流”在 HTTP/3 里用来实现控制和推送,近似地对应 HTTP/2 的 0 号流。由于流管理被“下放”到了 QUIC所以 HTTP/3 里帧的结构也变简单了。帧头只有两个字段:类型和长度,而且同样都采用变长编码,最小只需要两个字节。
![](/Users/lbp/Desktop/GitHub/knowledge-kit/assets/HTTP3Frame.png)
![](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/HTTP3Frame.png)
HTTP/3 里的帧仍然分成数据帧和控制帧两类HEADERS 帧和 DATA 帧传输数据,但其他一些帧因为在下层的 QUIC 里有了替代,所以在 HTTP/3 里就都消失了,比如 RST_STREAM、WINDOW_UPDATE、PING 等。