前言
这篇文章实话说我有点虚,因为平时都不怎么研究这一块的,然后涉及到的知识点超多,我只能到处看看资料总结一下相关信息,所以在此我只想说句:
本文章内容只代表个人立场,有错必改!
原本打算一次性总结,后来越扯越多超过字数限制了,就干脆做成http系列文章了,不定时更新原有内容(发现哪里出错的话),不定时新增系列文章,请见谅!
因为之前写得太臃肿又不够详细,最近刚好复习到这一块的内容,所以决定把这些文章都拆分成更加细致一点,补充详细内容,优化排版布局,目前来看还是应该的,因为自身时间问题和平台编译的问题迟迟未改,只好等都改完之后才发出来。
网络协议系列 — TCP、UDP、SOCKET与参考模型
传输编码优化
http在传输数据时可以原样传输,也可以通过编码提升船速效率,可以有效处理大量访问请求,但是编码操作需要额外消耗更多的CPU等资源.
报文与实体差异
报文(message): http通信基本单位,由8位组字节组成.
实体(entity): 作为请求或者响应的有效载荷数据被传输,内容由实体首部和实体主体组成
通常两者相同,只有当传输过程中进行编码操作时,实体主体的内容发生变化才与报文产生差异.
内容编码
指定应用在实体内容上的编码格式,并保持实体信息原样压缩,由客户端接收并负责解码
- gzip(GNU zip)
- compress(UNIX 系统的标准压缩)
- deflate(zlib)
- identity(不编码)
分块传输编码
一般用于大容量数据传输,把数据分割成多块传输能让浏览器逐步显示页面
分块传输会将实体主体分成多块,每一块用十六进制来标记块的大小,而实体主体的最后一块会使用"0(CR+LF)"来标记
多数据多部分对象集合
MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
http一份报文可以含有多种不同类型实体,常用于图片或文件文本等上传
multipart/form-data
可用于HTML表单从浏览器发送信息给服务器。作为多部分文档格式,它由边界线(一个由'--'开始的字符串)划分出的不同部分组成。每一部分有自己的实体,以及自己的 HTTP 请求头,Content-Disposition和 Content-Type 用于文件上传领域,最常用的 (Content-Length 因为边界线作为分隔符而被忽略)。
Content-Type: multipart/form-data; boundary=aBoundaryString (other headers associated with the multipart document as a whole) --aBoundaryString Content-Disposition: form-data; name="myFile"; filename="img.jpg" Content-Type: image/jpeg (data) --aBoundaryString Content-Disposition: form-data; name="myField" (data) --aBoundaryString (more subparts) --aBoundaryString--
表单
<form action="http://localhost:8000/" method="post" enctype="multipart/form-data">
<input type="text" name="myTextField">
<input type="checkbox" name="myCheckBox">Check</input>
<input type="file" name="myFile">
<button>Send the file</button>
</form>
请求
POST / HTTP/1.1 Host: localhost:8000 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Upgrade-Insecure-Requests: 1 Content-Type: multipart/form-data; boundary=---------------------------8721656041911415653955004498 Content-Length: 465 -----------------------------8721656041911415653955004498 Content-Disposition: form-data; name="myTextField" Test -----------------------------8721656041911415653955004498 Content-Disposition: form-data; name="myCheckBox" on -----------------------------8721656041911415653955004498 Content-Disposition: form-data; name="myFile"; filename="test.txt" Content-Type: text/plain Simple file. -----------------------------8721656041911415653955004498--
multipart/byteranges
用于把部分的响应报文发送回浏览器。当发送状态码206Partial Content 时,这个MIME类型用于指出这个文件由若干部分组成,每一个都有其请求范围。就像其他很多类型Content-Type使用分隔符来制定分界线。每一个不同的部分都有Content-Type这样的HTTP头来说明文件的实际类型,以及 Content-Range来说明其范围。
HTTP/1.1 206 Partial Content Accept-Ranges: bytes Content-Type: multipart/byteranges; boundary=3d6b6a416f9b5 Content-Length: 385 --3d6b6a416f9b5 Content-Type: text/html Content-Range: bytes 100-200/1270 eta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta name="vieport" content --3d6b6a416f9b5 Content-Type: text/html Content-Range: bytes 300-400/1270 -color: #f0f0f2; margin: 0; padding: 0; font-family: "Open Sans", "Helvetica --3d6b6a416f9b5--
获取部分范围请求
一种可在意外断开请求的情况下从上次中断处开始恢复下载,需要指明指定范围
Range: bytes=start-end
请求资源的部分内容(不包括响应头的大小),单位是byte,即字节,从0开始.
如果服务器能够正常响应的话,服务器会返回 206 Partial Content
的状态码及说明.
如果不能处理这种Range的话,就会返回整个资源以及响应状态码为 200 OK
.
内容协商返回
同一个站点可能存在多份相同内容页面,例如多语言., 内容协商机制就是指客户端和服务端就响应的资源内容进行交涉,然后得出合适的内容,已语言,字符集,编码方式等作为判断的基准响应请求
- Accept
- Accept-Charset
- Accept-Encoding
- Accept-Language
- Content-Language
协商类型有三种
服务器驱动(Server-driven Negotiation)
以请求头的信息为参考服务器自动处理
客户端驱动(Agent-driven Negotiation)
由客户端进行内容协商,从浏览器显示的可选列表中手动选择.
也可以用Javascript脚本自动选择
服务器驱动(Server-driven Negotiation)
两者共同协商
Http1.0 和 Http1.x的区别
1.x可扩展性更强大
- 在消息中增加版本号,用于兼容性判断
- 增加了
OPTIONS
方法,它允许客户端获取一个服务器支持的方法列表 - 在请求消息中包含了
Upgrade
头域,通过该头域,客户端可以让服务器知道它能够支持的其它备用通信协议,服务器可以据此进行协议切换,使用备用协议与客户端进行通信
缓存
1.0缓存
- 使用
Expire
头域来判断资源的fresh或stale,并使用条件请求(conditional request)
来判断资源是否仍有效 - 定义了
Pragma:no-cache
头域,客户端使用该头域说明请求资源不能从cache中获取,而必须回源获取
1.1缓存
- 增加了
Cache-Control
头域(请求消息和响应消息都可使用),它支持一个可扩展的指令子集 - 引入
ETag
头域用于重激活机制,它的值entity tag
可以用来唯一的描述一个资源。请求消息中可以使用If-None-Match
头域来匹配资源的entity tag是否有变化 - 引入
Vary
头域,该头域列出了请求消息中需要包含哪些头域用于内容协商
带宽优化
1.1在请求消息中引入了range
头域,它允许只请求资源的某个部分。在响应消息中Content-Range
头域声明了返回的这部分对象的偏移值和长度。如果服务器相应地返回了对象所请求范围的内容,则响应码为206(Partial Content)
1.1加入新的状态码100(Continue)
。客户端事先发送一个只带头域的请求,如果服务器因为权限拒绝了请求,就回送响应码401(Unauthorized)
;如果服务器接收此请求就回送响应码100,客户端就可以继续发送带实体的完整请求了, 1.0的客户端可以在请求消息中加入Expect
头域,并将它的值设置为100-continue
达到相同目的
长连接
1.0请求
浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求
要建立长连接,可以在请求消息中包含Connection: Keep-Alive
头域,如果服务器愿意维持这条连接,在响应消息中也会包含一个Connection: Keep-Alive
的头域。同时,可以加入一些指令描述该长连接的属性,如max,timeout
等
- 一个包含若干个头域名的列表,声明仅限于一次hop连接的头域信息
- 任意值,本次连接的非标准选项,如Keep-Alive等
- close值,表示消息传送完成之后关闭长连接
通常,HTTP/1.0的Proxy不支持Connection头域
1.1请求
支持长连接(PersistentConnection)
和请求的流水线(Pipelining)
处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟
允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容
客户端和源服务器之间的消息传递可能要经过很多中间节点的转发,这是一种逐跳传递(hop-by-hop)
。HTTP/1.1相应地引入了hop-by-hop
头域,这种头域仅作用于一次hop,而非整个传递路径。每一个中间节点(如Proxy,Gateway)接收到的消息中如果包含Connection头域,会查找Connection头域中的一个头域名列表,并在将消息转发给下一个节点之前先删除消息中这些头域
消息传递
HTTP消息中可以包含任意长度的实体,通常1.0使用Content-Length
来给出消息结束标志。但是,对于很多动态产生的响应,只能通过缓冲完整的消息来判断消息的大小,但这样做会加大延迟。如果不使用长连接,还可以通过连接关闭的信号来判定一个消息的结束。
1.1中引入了Transfer-Encoding:chunked
来解决上面这个问题,发送方将消息分割成若干个任意大小的数据块,每个数据块在发送时都会附上块的长度,最后用一个零长度的块作为消息结束的标志。这种方法允许发送方只缓冲消息的一个片段,避免缓冲整个消息带来的过载。
1.0中,有一个Content-MD5
的头域,要计算这个头域需要发送方缓冲完整个消息后才能进行。而1.1中,采用chunked分块传递的消息在最后一个块(零长度)结束之后会再传递一个拖尾(trailer),它包含一个或多个头域,这些头域是发送方在传递完所有块之后再计算出值的。发送方会在消息中包含一个Trailer头域告诉接收方这个拖尾的存在。
Host头域
1.0请求消息中的URL并没有传递主机名(hostname)
1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)
。此外,服务器应该接受以绝对路径标记的资源请求。
错误提示
1.0中只定义了16个状态响应码
1.1中新增了24个状态响应码,引入Warning
头域,增加对错误或警告信息的描述
内容协商
为了满足互联网使用不同母语和字符集的用户,一些网络资源有不同的语言版本(如中文版、英文版)。1.0定义了内容协商(contentnegotiation)
的概念,也就是说客户端可以告诉服务器自己可以接收以何种语言(或字符集)表示的资源
HTTP1.x缺点?
- HTTP 协议是没有状态,导致每次请求都必须附上所有信息;
- 两个报文之间的 header 通常非常相似,但它们仍然在连接中重复传输且没有经过压缩;
- (HTTP/1.0)每次请求都需要重新建立连接,可以添加头
Connection: keep-alive
建立持久连接; - 即使复用持久连接也是同步次序方式进行的,即服务器要处理完上一个才会进行下一个;
- 浏览器对同一域名下同时开启持久连接数限制大概在五个左右;
HTTP2改进?
传输协议
HTTP1.x是以纯文本的形式进行通信的,HTTP2彻底使用二进制协议替换,头信息和数据体都是二进制,并且统称为帧:常见的帧例如传输头信息的Header帧、传输正文内容的Data帧。因为二进制协议解析起来更高效错误更少。
头信息
HTTP2使用HPACK算法对头部进行压缩,基本原理:客户端和服务端分别缓存一份索引表,如果头部存在于索引表,则用对应的索引值;否则进行霍夫曼编码,并加入索引表,简单来说既避免了重复header的传输,又减小了需要传输数据的大小
传输
HTTP2会将一个TCP连接切分成多个流,每个流都有自己的ID,流是有优先级的虚拟通道,可以是服务器和客户端互相发送。HTTP2将多个请求分到不同的流中然后将请求内容拆分成更小的信息和帧,并对它们采用二进制格式编码传输,这些帧可以打散乱序发送然后根据每个帧首部的流标识符重新组装,并且可以根据优先级决定处理流数据的顺序。
服务器推送
HTTP2允许服务器未经请求主动向客户端发送资源,通过一个叫服务器推送的机制来提前请求。
通过推送那些服务器任务客户端将会需要的内容到客户端的缓存中,避免往返的延迟。
有一篇挺详细的分析文章推荐看看: HTTP/2之服务器推送(Server Push)最佳实践
例子
假设有一个简单的页面,他首屏只有三个请求,业务逻辑js,样式美化css,图片png。
HTTP1.x是串行请求的
(我知道我画的好丑,但是将就着看吧)
HTTP2是多路复用,可以同时发送,请求和应答可以不按顺序一一对应。
(我知道我画的好丑,但是将就着看吧)
HTTP2其实就是将三个请求换成三个流然后数据换成帧乱序发到同一个TCP连接中。这样既避免了串行堵塞的问题,还能减少连接数和前置操作,加快前端获取资源速度。
优点
HTTP2 帧机制是在 HTTP/1.x 语法和底层传输协议之间增加了一个新的中间层,而没有从根本上修改它,即它是建立在经过验证的机制之上。Web 开发人员不需要在其使用的 API 中做任何更改来利用 HTTP 帧;当浏览器和服务器都可用时,HTTP2 将被打开并使用。
缺点
尽管看起来HTTP2大大改善请求的局限性,但是也逃脱不了是基于TCP协议的命运,TCP在处理包的时候是严格控制顺序的。
如果其中一个数据包出错,TCP需要等它重新发送过来才能继续进行后续操作,虽然HTTP2通过优化处理机制实现并行内容多路传输,然而中间并没有关联的数据。
Google的QUIC协议就很好改善这问题了,我不熟悉就不说了。
Http连接管理
HTTP 的连接管理适用于两个连续节点之间的连接,如 hop-by-hop,而不是 end-to-end。当模型用于从客户端到第一个代理服务器的连接和从代理服务器到目标服务器之间的连接时(或者任意中间代理)效果可能是不一样的。HTTP 协议头受不同连接模型的影响,比如 Connection
和 Keep-Alive
,就是 hop-by-hop 协议头,它们的值是可以被中间节点修改的。
短连接
HTTP 最早期的模型,也是 HTTP/1.0 的默认模型(如果没有指定 Connection 协议头,或者是值被设置为 close)。每一个 HTTP 请求都由它自己独立的连接完成;这意味著发起每一个 HTTP 请求之前都会有一次 TCP 握手,而且是连续不断的。
TCP 协议握手本身就是耗费时间的,所以 TCP 可以保持更多的热连接来适应负载。短连接破坏了 TCP 具备的能力,新的冷连接降低了其性能。
而在 HTTP/1.1 中,只有当 Connection 被设置为 close 时才会用到这个模型。
这个简单的模型对性能有先天的限制:打开每一个 TCP 连接都是相当耗费资源的操作。客户端和服务器端之间需要交换好些个消息。当请求发起时,网络延迟和带宽都会对性能造成影响。现代浏览器往往要发起很多次请求(十几个或者更多)才能拿到所需的完整信息,证明了这个早期模型的效率低下。
一般项目需要进行大量请求场景,如果每个请求都进行串行执行会消耗大量的内存资源,引发自身的性能问题,但是如果每个请求都进行并行执行的话,会导致服务器在同一时间内处理大量请求,造成自身的效率问题。所以浏览器一般都会把并行请求限制在一定数量内,一般大概五个左右吧(我大概估算,没进行过验证的)。
缺点:
- 创建新连接耗费的时间;
- TCP 连接的性能只有在该连接被使用一段时间后(热连接)才能得到改善;
持久连接
而HTTP/1.1(以及 HTTP/1.0 的各种增强版本)允许HTTP在请求结束之后将TCP连接保持打开状态,以便为未来的HTTP请求重用现存的连接。一个长连接会保持一段时间,重复用于发送一系列请求,节省了新建 TCP 连接握手的时间,还可以利用 TCP 的性能增强能力。当然这个连接也不会一直保留著:连接在空闲一段时间后会被关闭(服务器可以使用 Keep-Alive
协议头来指定一个最小的连接保持时间)。
HTTP/1.0+ keep-alive
客户端可以通过包含Connection: Keep-Alive
首部请求将一条连接保持在打开状态,如果服务器愿意为下一条请求将连接保持在打开状态,就在响应中包含相同的首部。如果响应中没有 Connection: Keep-Alive 首部, 客户端就认为服务器不支持 keep-alive, 会在发回响应报文之后关闭连接。首部 作用 timeout 响应首部发送的。 它代表服务器希望将连接保持在活跃状态的时间。 但这并不是绝对 max 响应首部发送的。 它代表服务器还希望为多少个事务保持此连接的活跃状态。 但这并不是绝对 Keep-Alive 首部还可支持任意未经处理的属性, 这些属性主要用于诊断和调试。语法为 name=value 例如
Keep-Alive: max=5, timeout=3000, abc=123;
HTTP/1.0 里默认并不适用长连接。把 Connection 设置成 close 以外的其它参数都可以让其保持长连接,通常会设置为 retry-after。
在 HTTP/1.1 里,默认就是长连接的,协议头都不用再去声明它(但我们还是会把它加上,万一某个时候因为某种原因要退回到 HTTP/1.0 呢)。
- HTTP/1.1 persistent
现在HTTP/1.1 逐渐停止了对 keep-alive 连接的支持, 用一种名为持久连接(persistent connection) 的改进型设计取代了它。
与 HTTP/1.0+ 的 keep-alive 连接不同,HTTP/1.1 持久连接在默认情况下是激活的。 除非特别指明,否则 HTTP/1.1 假定所有连接都是持久的。要在事务处理结束之后将连接关闭,HTTP/1.1 应用程序必须向报文中显式地添加一个Connection: close首部。这是与以前的 HTTP 协议版本很重要的区别,在以前的版本中,keep-alive 连接要么是可选的,要么根本就不支持。这种连接相当于是在HTTP/1.1之上默认开启keep-alive
缺点:
- 就算是在空闲状态,它还是会消耗服务器资源;
- 在重负载时,还有可能遭受 DoS attacks 攻击;
blind relay
特指那些不理解 Connection 首部,而且不知道在沿着转发链路将其发送出去之前,应该将该首部删除的代理。很多老的或简单的代理都 是 盲中继(blind relay)
,它们只是将字节从一个连接转发到另一个连接中去,不对 Connection 首部进行特殊的处理。
流水线
默认情况下,HTTP 请求是按顺序发出的。下一个请求只有在当前请求收到应答过后才会被发出。由于会受到网络延迟和带宽的限制,在下一个请求被发送到服务器之前,可能需要等待很长时间。
流水线是在同一条长连接上发出连续的请求,而不用等待应答返回。这样可以避免连接延迟。理论上讲,性能还会因为两个 HTTP 请求有可能被打包到一个 TCP 消息包中而得到提升。就算 HTTP 请求不断的继续,尺寸会增加,但设置 TCP 的 MSS(Maximum Segment Size) 选项,仍然足够包含一系列简单的请求。
并不是所有类型的 HTTP 请求都能用到流水线:只有 idempotent 方式,比如 GET、HEAD、PUT 和 DELETE 能够被安全的重试:如果有故障发生时,流水线的内容要能被轻易的重试。
今天,所有遵循 HTTP/1.1 的代理和服务器都应该支持流水线,虽然实际情况中还是有很多限制:一个很重要的原因是,仍然没有现代浏览器去默认支持这个功能。
- Web 开发者并不能轻易的遇见和判断那些搞怪的 代理服务器 的各种莫名其妙的行为。
- 正确的实现流水线式复杂的:传输中的资源大小,多少有效的 往返时延 RTT(Round-Trip Time) 会被用到,还有有效带宽,流水线带来的改善有多大的影响范围。不知道这些的话,重要的消息可能被延迟到不重要的消息后面。这个重要性的概念甚至会演变为影响到页面布局!因此 HTTP 流水线在大多数情况下带来的改善并不明显。
- 流水线受制于 队头阻塞 Head-of-line blocking (HOL blocking) 问题。
由于这些原因,流水线已经被更好的算法给代替,如 multiplexing
,已经用在 HTTP/2。
域名分片
除非你有紧急而迫切的需求,不要使用这一过时的技术,升级到 HTTP/2 就好了。在 HTTP/2 里,做域名分片就没必要了:HTTP/2 的连接可以很好的处理并发的无优先级的请求。域名分片甚至会影响性能。大多数 HTTP/2 的实现还会使用一种称作连接凝聚的技术去尝试合并被分片的域名。
浏览器为每个域名建立多个连接,以实现并发请求。现在比较常用的并发连接数已经增加到 6 条。如果尝试大于这个数字,就有触发服务器 DoS 保护的风险。
如果服务器端想要更快速的响应网站或应用程序的应答,它可以迫使客户端建立更多的连接。例如,不要在同一个域名下获取所有资源,假设有个域名是 www.example.com
,我们可以把它拆分成好几个域名:www1.example.com
、www2.example.com
、www3.example.com
。所有这些域名都指向同一台服务器,浏览器会同时为每个域名建立 6 条连接(在我们这个例子中,连接数会达到 18 条)。这一技术被称作域名分片。
HTTP/2 长连接与多路复用(multiplexing)
在HTTP/2中,客户端向某个域名的服务器请求页面的过程中,只会创建一条TCP连接,即使这页面可能包含上百个资源。而之前的HTTP/1.x一般会创建6-8条TCP连接来请求这100多个资源。单一的连接应该是HTTP2的主要优势,单一的连接能减少TCP握手带来的时延,避免了创建多个TCP连接带来的网络开销,提高了吞吐量。(对SSL握手跟TCP滑动窗口的慢启动消耗较少尤为明显)
帧(frame)
HTTP/2 是基于帧(frame)的协议。采用分帧是为了将重要信息都封装起来, 让协议的解析方可以轻松阅读、解析并还原信息。帧(frame)
是HTTP/2中数据传输的最小单位,因此帧不仅要细分表达HTTP/1.x中的各个部份,也优化了HTTP/1.x表达得不好的地方,同时还增加了HTTP/1.x表达不了的方式。
流(Stream)
服务器和客户端在HTTP/2连接内用于交换帧数据的独立双向序列,逻辑上可看做一个较为完整的交互处理单元,即表达一次完整的资源请求-响应数据交换流程;一个业务处理单元,在一个流内进行处理完毕,这个流生命周期完结。
特点如下:
- 一个HTTP/2连接可同时保持多个打开的流,任一端点交换帧
- 流可被客户端或服务器单独或共享创建和使用
- 流可被任一端关闭
- 在流内发送和接收数据都要按照顺序
- 流的标识符自然数表示,1~2^31-1区间,有创建流的终端分配
- 流与流之间逻辑上是并行、独立存在
多路复用(multiplexing)
在一个TCP连接上,我们可以向对方不断发送一个个的消息,这里每一个消息看成是一帧,而每一帧有个stream identifier 的字段标明这一帧属于哪个 流,然后在对方接收时,根据 stream identifier 拼接每个 流 的所有帧组成一整块数据。我们把 HTTP/1.x 每个请求都当作一个 流,那么请求化成多个流,请求响应数据切成多个帧,不同流中的帧交错地发送给对方,这就是HTTP/2中的 多路复用。
从上图我们可以留意到:
- 不同的流在交错发送;
- HEADERS 帧在 DATA 帧前面;
- 流的ID都是奇数,说明是由客户端发起的,这是标准规定的,那么服务端发起的就是偶数了。
多路复用让HTTP连接变得很廉价,只需要创建一个新流即可,这不需要多少时间,而在 HTTP/1.x 时代却要经历三次握手时间或者队首阻塞等问题。而且创建新流默认是无限制的,也就是可以无限制的并行请求下载。不过,HTTP/2 还是提供了 SETTINGS_MAX_CONCURRENT_STREAMS
字段在 SETTINGS 帧
上设置,可以限制并发流数目,标准上建议不要低于 100 以保证性能。
实际的传输可能是这样的:
需要抽象化一些,就好理解了:
- 每一个帧可看做是一个学生,流可以认为是组(流标识符为帧的属性值),一个班级(一个连接)内学生被分为若干个小组,每一个小组分配不同的具体任务。
HTTP/1.x
一次请求-响应,建立一个连接,用完关闭;每一个小组任务都需要建立一个班级,多个小组任务多个班级,1:1比例HTTP/1.1 Pipeling
解决方式为,若干个小组任务排队串行化单线程处理,后面小组任务等待前面小组任务完成才能获得执行机会,一旦有任务处理超时等,后续任务只能被阻塞,毫无办法,也就是人们常说的线头阻塞HTTP/2
多个小组任务可同时并行(严格意义上是并发)在班级内执行。一旦某个小组任务耗时严重,但不会影响到其它小组任务正常执行- 针对一个班级资源维护要比多个班级资源维护经济多了,这也是多路复用出现的原因。
(更多内容请自行查阅,本节到此为止了。)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。