<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Http2 on Tech Explorer</title><link>https://byronhe.com/categories/http2/</link><description>C++、Linux、算法、数据结构与密码学的学习笔记与实践记录。</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>© 2026 BH</copyright><lastBuildDate>Wed, 08 Mar 2017 00:00:00 +0000</lastBuildDate><atom:link href="https://byronhe.com/categories/http2/index.xml" rel="self" type="application/rss+xml"/><item><title>Proxygen http2 代码分析</title><link>https://byronhe.com/post/Proxygen-http2-code-analysis/</link><pubDate>Wed, 08 Mar 2017 00:00:00 +0000</pubDate><guid>https://byronhe.com/post/Proxygen-http2-code-analysis/</guid><description>&lt;p&gt;Proxygen 的整体架构&#10;&lt;figure&gt;&#10; &lt;img class="my-0 rounded-md" loading="lazy" decoding="async" alt="image" src="https://raw.githubusercontent.com/facebook/proxygen/master/CoreProxygenArchitecture.png"&gt;&lt;/figure&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;一个 HTTPSession 对应一个 tcp 连接。&lt;/p&gt;&#10;&lt;p&gt;HTTPSession 中包含HTTPCodec ，HTTPCodec用来在 HTTPMessage(Request/Response) 和 字节流之间做转换（就是解析/序列化）。&lt;/p&gt;&#10;&lt;p&gt;一个 HTTPTransaction 对应一个 HTTP2 的Stream ，也就是一次 Req/Resp&#10;Handler 是业务逻辑处理的基类。&lt;/p&gt;</description><content:encoded>&lt;p&gt;Proxygen 的整体架构&#10;&lt;figure&gt;&#10; &lt;img class="my-0 rounded-md" loading="lazy" decoding="async" alt="image" src="https://raw.githubusercontent.com/facebook/proxygen/master/CoreProxygenArchitecture.png"&gt;&lt;/figure&gt;&#10;&lt;/p&gt;&#10;&lt;p&gt;一个 HTTPSession 对应一个 tcp 连接。&lt;/p&gt;&#10;&lt;p&gt;HTTPSession 中包含HTTPCodec ，HTTPCodec用来在 HTTPMessage(Request/Response) 和 字节流之间做转换（就是解析/序列化）。&lt;/p&gt;&#10;&lt;p&gt;一个 HTTPTransaction 对应一个 HTTP2 的Stream ，也就是一次 Req/Resp&#10;Handler 是业务逻辑处理的基类。&lt;/p&gt;&#10;&lt;p&gt;其中 HTTP2 部分由几个类构成：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;codec/HTTPCodec.h&lt;/li&gt;&#10;&lt;li&gt;codec/HTTP2Framer.cpp&lt;/li&gt;&#10;&lt;li&gt;codec/HTTP2Codec.cpp , HTTPParallelCodec.cpp&lt;/li&gt;&#10;&lt;li&gt;codec/Compress/HeaderCodec.cpp,HPACKCodec.cpp&lt;/li&gt;&#10;&lt;li&gt;session/HTTPSession.cpp&lt;/li&gt;&#10;&lt;li&gt;session/HTTPTransacion.cpp&lt;/li&gt;&#10;&lt;li&gt;session/HTTP2PriorityQueue.cpp&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&#10;&lt;h2 class="relative group"&gt;1. HTTPCodec.h&#10; &lt;div id="1-httpcodech" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#1-httpcodech" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;定义了 HTTPCodec 这个基类，定义了用来在 内部的 HTTP Request/Response 和 字节流之间做转换的公共接口，是HTTP1.1/SPDY/HTTP2 的公共基类。具体的HTTP2/HTTP1.1等各种协议的编解码，实现在 HTTP1.1/SPDY/HTTP2 等子类中。&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;1) HTTPCodec&#10; &lt;div id="1-----httpcodec" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#1-----httpcodec" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;HTTPCodec 是 HTTP1.1/ HTTP2 接口的超集，即HTTP1.1也被当成 HTTP2 实现&lt;/p&gt;&#10;&lt;p&gt;i. 首先所有的 子类都要支持 StreamID，HTTP1.1 由于有KeepAlive，看成有多个Stream。&#10;ii. onIngress()，传入输入数据，驱动解析。&#10;iii. generateHeader()/ generateBody() /generateChunkHeader() /generateGoaway()/ generatePingRequest()/ generatePriority() 等，是 http1.1/http2 的超集。HTTP1xCodec.cpp 是没有实现HTTP2 的这些Frame 的generateXXX函数。HTTP1.1&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;2) PriorityQueue，优先级队列。&#10; &lt;div id="2-----priorityqueue优先级队列" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#2-----priorityqueue%e4%bc%98%e5%85%88%e7%ba%a7%e9%98%9f%e5%88%97" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;Session/HTTP2PriorityQueue.cpp 实现了这个接口类&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;3) HTTPCodec::Callback 类&#10; &lt;div id="3------httpcodeccallback-类" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#3------httpcodeccallback-%e7%b1%bb" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;解析的过程中，需要通知 HTTPCodec 的使用者做一些操作，因此有个 接口类 HTTPCodec::Callback，HTTPCodec 的使用者实现 Callback 的子类，传给 HTTPCodec 的子类，HTTPCodec 的子类在解析过程中解析出来的各种消息都回调这个callback。&#10;Callback 的主要方法有:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;onMessageBegin()&lt;/li&gt;&#10;&lt;li&gt;onHeadersComplete() // HeaderList 接收完&lt;/li&gt;&#10;&lt;li&gt;onBody() &#9;&#9;// Body 开始&lt;/li&gt;&#10;&lt;li&gt;onMessageComplete() //Message 整个接收完&lt;/li&gt;&#10;&lt;li&gt;onWindowUpdate() // 收到 WindowUpdate Frame&lt;/li&gt;&#10;&lt;li&gt;onPriority()， //收到 Priority Frame等&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;顾名思义，处理HTTPMessage 开始事件，收到各种 HTTP2 Frame 等等。&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;2. HTTP2Framer.cpp&#10; &lt;div id="2-http2framercpp" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#2-http2framercpp" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;10种Frame 的 解析/序列化 工具函数，parseXXXFrame, writeXXXFrame，最底层。供HTTP2Codec 使用。&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;3. HTTP2Codec&#10; &lt;div id="3-http2codec" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#3-http2codec" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;Framing Layer，即处理 HTTPMesage , HTTP2 Frame 和 输入/输出字节流之间的 解析/序列化。实现了HTTPParallelCodec(HTTP2和SPDY的公共基类，HTTPCodec 的子类)，HeaderCodec两个接口类&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;1) 输入字节流的解析的时候，做:&#10; &lt;div id="1-----输入字节流的解析的时候做" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#1-----%e8%be%93%e5%85%a5%e5%ad%97%e8%8a%82%e6%b5%81%e7%9a%84%e8%a7%a3%e6%9e%90%e7%9a%84%e6%97%b6%e5%80%99%e5%81%9a" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&#10;&lt;h4 class="relative group"&gt;i. HEADERS Frame，&#10; &lt;div id="i--headers-frame" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#i--headers-frame" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;做各种 Header 的变换处理。&lt;/p&gt;&#10;&#10;&lt;h4 class="relative group"&gt;ii. PRIORITY&#10; &lt;div id="ii----priority" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ii----priority" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&#10;&lt;h2 class="relative group"&gt;4. compress/HeaderCodec.cpp&#10; &lt;div id="4-compressheadercodeccpp" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#4-compressheadercodeccpp" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;HeaderCodec 是 Header List 的编解码器。HeaderCodec解码的结果通过 HeaderCodec::StreamingCallback接口类通知给使用者（即HTTP2Codec）。HeaderCodec::StreamingCallback主要有个 onHeader(name, value) 接口(HTTP2Codec实现了)。&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;5. compress/HPACKCodec.cpp&#10; &lt;div id="5-compresshpackcodeccpp" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#5-compresshpackcodeccpp" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;HPACK保存 int &amp;ndash;&amp;gt; string 的映射，通过发送 int， 代替 string 来压缩。&lt;/p&gt;&#10;&lt;p&gt;HPACK编码，主要需要实现动态表，静态表，Huffman encoding，Header序列化/解析。&lt;/p&gt;&#10;&lt;p&gt;HPACKCodec 主要有 encode(vector&lt;Header&gt;)/decode(Buffer) 两个接口。重要成员变量：&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;HPACKEncoder&lt;/span&gt; &lt;span class="n"&gt;encoder_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;HPACKDecoder&lt;/span&gt; &lt;span class="n"&gt;decoder_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;实际的 动态表/静态表 逻辑，是一个HeaderTable，主要数据结构就是vector&lt;HPACKHeader&gt; + ，&lt;/p&gt;&#10;&lt;p&gt;HPACKDecoder 里面的动态表对应的是 HPACKContext，先 peek 一个字节，判断是否用了HPACKDecodeBuffer来解码&lt;/p&gt;&#10;&lt;p&gt;Integer比特编解码，literal编解码，都实现在 HPACKDecodeBuffer / HPACKEncodeBuffer里面。&lt;/p&gt;&#10;&lt;p&gt;Huffman encoding 实际使用的是 256位的trie，不是2位的，为了优化性能。&lt;/p&gt;&#10;&lt;p&gt;在 HeaderTable.cpp 中，可以看到，实际的 vector 是当成一个 环形队列来用的，&#10;实际是 把 RFC 中规定的 [ 1 &amp;mdash; n ] 的区间，逆向映射到 这个环形队列中，即 index 1 是，对应到 环形队列的 尾，index n 是对应到环形队列的头。&#10;这样，按照 RFC，增加 Header 进来的时候，应该是加在 1 前面，并把所有的已有 Header 往后挪1个位置，实现上就可以不用做 “挪动”，而且已有的 name&amp;ndash;&amp;gt;index 的映射也不用改。这是一种实现上的小技巧。&lt;/p&gt;&#10;&lt;p&gt;并用 一个&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;unordered_map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;的形式存储 Header.name 到一组 vector 中的 index 的映射，这是由于 有 相同 name ，对应多个 value 的情况，而且要支持 “查找 name+value 匹配” 和 ”查找 name 匹配“ 两种查找。&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;6. session/HTTP2PriorityQueue.cpp&#10; &lt;div id="6-sessionhttp2priorityqueuecpp" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#6-sessionhttp2priorityqueuecpp" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;每一个 Stream都 依赖一个 Stream 或者 Stream 0。&#10;一个 Stream A 依赖 Stream B ，那么 A 就是 B 的子节点。形成依赖树。&#10;Stream 0 是树的根节点。&lt;/p&gt;&#10;&lt;p&gt;HTTP2PriorityQueue实现了PriorityQueue接口类，实现了 &lt;code&gt;addPriorityNode(StreamID id, StreamID parent)&lt;/code&gt; 接口&lt;/p&gt;&#10;&lt;p&gt;主要的逻辑实现在 Node这个内部类里面。&lt;/p&gt;&#10;&lt;p&gt;PriorityQueue 的数据成员，主要是一个 &lt;code&gt;unorder_map&amp;lt;streamID, Node&amp;gt;&lt;/code&gt;&lt;/p&gt;&#10;&lt;p&gt;Node内部的数据成员：&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Node&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;HTTP2PriorityQueue&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;queue_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//属于哪个 PriorityQueue&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Node&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;parent_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt; &#9;&#9;&lt;span class="c1"&gt;//树中的父节点&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;HTTPCodec&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;StreamID&lt;/span&gt; &lt;span class="n"&gt;id_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;//&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint16_t&lt;/span&gt; &lt;span class="n"&gt;weight_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;//权重&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;HTTPTransaction&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;txn_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isPermanent_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;enqueued_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;//enqueued 表示在 有输出数据的队列中&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;totalEnqueuedWeight_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint64_t&lt;/span&gt; &lt;span class="n"&gt;totalChildWeight_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;children_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 子节点&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unique_ptr&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt; &lt;span class="n"&gt;self_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;folly&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;IntrusiveListHook&lt;/span&gt; &lt;span class="n"&gt;enqueuedHook_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//一个侵入式链表&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;folly&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;IntrusiveList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;enqueuedHook_&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;enqueuedChildren_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;有输出数据等待发送 (pending Egress) 的 HTTPTransaction ，会加入&lt;/p&gt;&#10;&lt;p&gt;signalPendingEgress() ， 通知 HTTP2PriorityQueue 某一个 Stream 产生了输出数据。&#10;内部实现是把 这 Stream加入&lt;/p&gt;&#10;&lt;p&gt;clearPendingEgress()， 通知一个 Stream 发完了 输出数据。&lt;/p&gt;&#10;&lt;p&gt;addOrUpdatePriorityNode()，&lt;/p&gt;&#10;&lt;p&gt;nextEgress() ， 获取有输出数据等待发送的 HTTPTransaction 的列表，列表的每个元素是 pair&amp;lt; HTTPTransaction * ，double weight &amp;gt; ，按照 weight 从大到小排列，列表中的所有weight 加起来等于1。&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;7. session/HTTPTransaction.cpp&#10; &lt;div id="7-sessionhttptransactioncpp" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#7-sessionhttptransactioncpp" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;HTTPTransaction 表示一次 Req／Resp，HTTPTransaction 需要和 HTTPSession 交互写入 HTTPMessage 所以提出了Transport 这个概念，这样依赖关系就是单向的，没有 HTTPTransaction – HTTPSession 之间不会产生双向依赖。实际处理业务的代码，定义成一个个 Handler，需要与Handler 交互，&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;1) HTTPTransaction::Transport&#10; &lt;div id="1-----httptransactiontransport" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#1-----httptransactiontransport" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;是 HTTPTransaction 的下层为 HTTPTransaction 提供的输出HTTPMessage 服务。(下层具体指的是 HTTPSession)。&lt;/p&gt;&#10;&lt;p&gt;Transport 的方法有：sendHeaders()/sendBody()/pauseIngress()/resumeIngress()/ sendPriority() / 等&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;2) HTTPTransactionHandler&#10; &lt;div id="2-----httptransactionhandler" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#2-----httptransactionhandler" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;是一个个业务Handler 的基类，Handler的方法有:onHeadersComplete()/onBody()/onChunk/onTrailers/onEgressPaused()/ onEgressResumed等，就是解析出 HTTP Message的各个部分，或者流控发现无法再写了时候的通知。&lt;/p&gt;&#10;&lt;p&gt;i. HTTPTransaction::Handler 有好几种,业务Handler 比如直接生成 ErrorPage 的 HTTPDirectResponseHandler就是生成 404 页面的 Handler，在其内部，实现 onHeadersComplete 方法，在这个方法内生成 回包数据，然后调用 HTTPTransaction 的 sendHeaders/sendBody 等方法发回给客户端。&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;3) HTTPTransactionIngressSM&#10; &lt;div id="3---httptransactioningresssm" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#3---httptransactioningresssm" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;由于 HTTPTransaction 要调用 Handler 的好几种方法，内部要记录当前已经处理到哪一步了，不能允许在任意时机，任意来的数据都触发回调，所以搞了两个状态机，HTTPTransactionIngressSM/ HTTPTransactionEgressSM 来明确地规定 回调可以触发的顺序。&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;4) HTTPTransaction 的重要成员变量：&#10; &lt;div id="4-------httptransaction-的重要成员变量" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#4-------httptransaction-%e7%9a%84%e9%87%8d%e8%a6%81%e6%88%90%e5%91%98%e5%8f%98%e9%87%8f" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;streamId, handler_ , transport_ ,egressState_ , ingressState_, recvWindow_ , sendWindow_, HTTP2PrioprityQueue::Handle queueHande_,&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;8. session/HTTPSession.cpp&#10; &lt;div id="8-sessionhttpsessioncpp" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#8-sessionhttpsessioncpp" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;HTTPSession 针对 HTTP2/HTTP1.1/SPDY的超集的，HTTPSession是一个 HTTPCodec::Callback（接受解析出来的各种 Frame），是 HTTPTransaction::Callback（供HTTPTransaction发送输出 HTTP Message）,是 FlowControlFilter::Callback（接受输出状态打开/关闭的通知）。&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;1) 重要成员变量：&#10; &lt;div id="1------重要成员变量" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#1------%e9%87%8d%e8%a6%81%e6%88%90%e5%91%98%e5%8f%98%e9%87%8f" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;folly&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;IOBufQueue&lt;/span&gt; &lt;span class="n"&gt;readBuf_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;folly&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;IOBufQueue&lt;/span&gt; &lt;span class="n"&gt;writeBuf_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StreamID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HTTPTransaction&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;transactions_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;HTTP2PriorityQueue&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FlowControlFilter&lt;/span&gt; &lt;span class="n"&gt;connFlowControl_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#9;&#9;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&#9;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&#10;&lt;h3 class="relative group"&gt;2) getNextToSend()&#10; &lt;div id="2-------getnexttosend" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#2-------getnexttosend" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;是做发送的，可以看到，proxygen 是按相对权重来分派带宽的。txnEgressQueue_.nextEgress() 取出当前可发送的 HTTPTransaction + 相对权重的列表，然后把可发送字节数 按照相对权重分给各个HTTPTransaction。&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;9. 细节&#10; &lt;div id="9-细节" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#9-%e7%bb%86%e8%8a%82" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&#10;&lt;h3 class="relative group"&gt;1) IOBufQueue&#10; &lt;div id="1---iobufqueue" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#1---iobufqueue" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;多处用到的基础类：IOBufQueue，Zero-Copy，引用计数。一个 Bufffer Chain，设计类似 linux kernel 的sk_buff, BSD 的 mbuf 。&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://github.com/facebook/folly/blob/master/folly/io/IOBuf.h" target="_blank" rel="noreferrer"&gt;https://github.com/facebook/folly/blob/master/folly/io/IOBuf.h&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; * An IOBuf is a pointer to a buffer of data. *&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; * IOBuf objects are intended to be used primarily for networking code, and are&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; * modelled somewhat after FreeBSD&amp;#39;s mbuf data structure, and Linux&amp;#39;s sk_buff structure.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; * IOBuf objects facilitate zero-copy network programming, by allowing multiple&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; * IOBuf objects to point to the same underlying buffer of data, using a&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; * reference count to track when the buffer is no longer needed and can be freed.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&#10;&lt;h3 class="relative group"&gt;2) HTTPHeaders&#10; &lt;div id="2----httpheaders" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#2----httpheaders" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;HTTPHeaders 有个性能优化，用了 静态完美hash函数，把常用的 83个 Header 各自唯一地hash 成1 字节，HeaderList 的查找使用 汇编实现的memchr。&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://github.com/facebook/proxygen/blob/master/proxygen/lib/http/HTTPHeaders.h" target="_blank" rel="noreferrer"&gt;https://github.com/facebook/proxygen/blob/master/proxygen/lib/http/HTTPHeaders.h&lt;/a&gt;&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;* Headers are stored as Name/Value pairs, in the order they are received on&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; * the wire. We hash the names of all common HTTP headers (using a static&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; * perfect hash function generated using gperf from HTTPCommonHeaders.gperf)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; * into 1-byte hashes (we call them &amp;#34;codes&amp;#34;) and only store these. We search&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; * them using memchr, which has an x86_64 assembly implementation with&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; * complexity O(n/16) ;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content:encoded></item><item><title>TrafficServer http2 代码分析</title><link>https://byronhe.com/post/TrafficServer-http2-code-analysis/</link><pubDate>Wed, 08 Mar 2017 00:00:00 +0000</pubDate><guid>https://byronhe.com/post/TrafficServer-http2-code-analysis/</guid><description>&lt;p&gt;TrafficServer 是Apache基金会的 HTTP/HTTP2 代理服务器。&lt;/p&gt;&#10;&lt;p&gt;TrafficServer 的 HTTP2 部分主要的代码在 :&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/HTTP2.h, HTTP2.cc&lt;/li&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/Http2Stream.h, Http2Stream.cc&lt;/li&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/Http2ClientSession.h, Http2ClientSession.cc&lt;/li&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/Http2ConnectionState.h, Http2ConnectionState.cc&lt;/li&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/ Http2DependencyTree.h, Http2DependencyTree.cc&lt;/li&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/HPACK.h, HPACK.cc&lt;/li&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/HuffmanCodec.h, HuffmanCodec.cc&lt;/li&gt;&#10;&lt;/ol&gt;</description><content:encoded>&lt;p&gt;TrafficServer 是Apache基金会的 HTTP/HTTP2 代理服务器。&lt;/p&gt;&#10;&lt;p&gt;TrafficServer 的 HTTP2 部分主要的代码在 :&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/HTTP2.h, HTTP2.cc&lt;/li&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/Http2Stream.h, Http2Stream.cc&lt;/li&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/Http2ClientSession.h, Http2ClientSession.cc&lt;/li&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/Http2ConnectionState.h, Http2ConnectionState.cc&lt;/li&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/ Http2DependencyTree.h, Http2DependencyTree.cc&lt;/li&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/HPACK.h, HPACK.cc&lt;/li&gt;&#10;&lt;li&gt;trafficserver/proxy/http2/HuffmanCodec.h, HuffmanCodec.cc&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&#10;&lt;h2 class="relative group"&gt;1. trafficserver/proxy/http2/HTTP2.h, HTTP2.cc&#10; &lt;div id="1--trafficserverproxyhttp2http2h-http2cc" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#1--trafficserverproxyhttp2http2h-http2cc" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;10种Frame 的struct定义，解析/序列化函数，HeaderList转换函数，一些常量定义&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;2. trafficserver/proxy/http2/Http2ClientSession.h, Http2ClientSession.cc&#10; &lt;div id="2--trafficserverproxyhttp2http2clientsessionh-http2clientsessioncc" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#2--trafficserverproxyhttp2http2clientsessionh-http2clientsessioncc" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;Http2ClientSession 处理 io event 事件，解析 FrameHeader，&lt;/p&gt;&#10;&lt;p&gt;调用顺序：&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Http2ClientSession::main_event_handler()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--&amp;gt; state_read_connection_preface()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--&amp;gt; state_start_frame_read()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--&amp;gt; state_process_frame_read() 解析出一个完整的Frame&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--&amp;gt; do_complete_frame_read()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;--&amp;gt; Http2ConnectionState::main_event_handler(HTTP2_SESSION_EVENT_RECV )&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&#10;&lt;h2 class="relative group"&gt;3. trafficserver/proxy/http2/Http2ConnectionState.h, Http2ConnectionState.cc&#10; &lt;div id="3--trafficserverproxyhttp2http2connectionstateh-http2connectionstatecc" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#3--trafficserverproxyhttp2http2connectionstateh-http2connectionstatecc" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;Http2ConnectionState，对应一个 HTTP2 连接，代码基本等价于 proxygen 的 HTTPSession，主要的成员变量：&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;双链表&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Http2Stream&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;//略挫，有个find_stream 用的遍历，改map好点。&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Http2ClientSession&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;HpackHandle&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;个，&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;DependencyTree&lt;/span&gt;&lt;span class="err"&gt;，&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Http2ConnectionSettingsclient_settings&lt;/span&gt; &lt;span class="n"&gt;server_settings&lt;/span&gt;&lt;span class="err"&gt;，连接的几个&lt;/span&gt; &lt;span class="n"&gt;Settings&lt;/span&gt; &lt;span class="err"&gt;配置项，一个&lt;/span&gt;&lt;span class="n"&gt;int数组&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;主要的方法：各个 rcv_xxx_frame() 和 send_xxx_frame(0&#10;Http2ConnectionState::main_event_handler(HTTP2_SESSION_EVENT_RECV )里面，解析输入的各种 Frame&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;rcv_data_frame, // HTTP2_FRAME_TYPE_DATA&lt;/li&gt;&#10;&lt;li&gt;rcv_headers_frame, // HTTP2_FRAME_TYPE_HEADERS&lt;/li&gt;&#10;&lt;li&gt;rcv_priority_frame, // HTTP2_FRAME_TYPE_PRIORITY&lt;/li&gt;&#10;&lt;li&gt;rcv_rst_stream_frame, // HTTP2_FRAME_TYPE_RST_STREAM&lt;/li&gt;&#10;&lt;li&gt;rcv_settings_frame, // HTTP2_FRAME_TYPE_SETTINGS&lt;/li&gt;&#10;&lt;li&gt;rcv_push_promise_frame, // HTTP2_FRAME_TYPE_PUSH_PROMISE&lt;/li&gt;&#10;&lt;li&gt;rcv_ping_frame, // HTTP2_FRAME_TYPE_PING&lt;/li&gt;&#10;&lt;li&gt;rcv_goaway_frame, // HTTP2_FRAME_TYPE_GOAWAY&lt;/li&gt;&#10;&lt;li&gt;rcv_window_update_frame, // HTTP2_FRAME_TYPE_WINDOW_UPDATE&lt;/li&gt;&#10;&lt;li&gt;rcv_continuation_frame, // HTTP2_FRAME_TYPE_CONTINUATION&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;还有发送各类 frame 的接口，send_data_frames()/send_headers_frame() / send_push_promise_frame() / send_rst_stream_frame() 等。&lt;/p&gt;&#10;&lt;p&gt;具体地：&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;rcv_data_frame :&#10; &lt;div id="rcv_data_frame-" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rcv_data_frame-" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;find_stream,然后检查stream的state是不是OPEN/HALF_CLOSE_LOCAL，去除 padding，处理END_STREAM flag，检查本端流量控制 window_size ，保存buffer，更新本地的window，发回 Connection 和 Stream Level 的WindowUpdate Frame。&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;rcv_headers_frame：&#10; &lt;div id="rcv_headers_frame" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rcv_headers_frame" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;find_stream/create_stream，处理padding，处理PRIORITY flag添加到 PriorityTree 里面，如果 Header Block 结束了（即有END_HEADERS FLAG），那就http2_decode_header_blocks() 做HPACK 解压缩，调用 Http2Stream 处理解析出的HeaderList&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;rcv_priority_frame:&#10; &lt;div id="rcv_priority_frame" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rcv_priority_frame" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;find_stream，reprioritize，重新调整树。&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;rcv_rst_stream_frame&#10; &lt;div id="rcv_rst_stream_frame" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rcv_rst_stream_frame" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&#10;&lt;h3 class="relative group"&gt;rcv_settings_frame:&#10; &lt;div id="rcv_settings_frame" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rcv_settings_frame" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;parse检查收到的各个配置项，更新到client_settings中，并发送SETTINGS_ACK&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;rcv_push_promise_frame 等&#10; &lt;div id="rcv_push_promise_frame-等" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rcv_push_promise_frame-%e7%ad%89" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;包括 rcv_ping_frame&lt;/p&gt;&#10;&lt;p&gt;rcv_goaway_frame:&lt;/p&gt;&#10;&lt;p&gt;rcv_window_update_frame&lt;/p&gt;&#10;&lt;p&gt;比较简单，略。&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;rcv_continuation_frame&#10; &lt;div id="rcv_continuation_frame" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rcv_continuation_frame" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;类似 rcv_headers_frame&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;send_data_frames_depends_on_priority&#10; &lt;div id="send_data_frames_depends_on_priority" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#send_data_frames_depends_on_priority" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;取了 DependencyTree的top()，&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;send_data_frames 等&#10; &lt;div id="send_data_frames-等" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#send_data_frames-%e7%ad%89" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;send_a_data_frame&lt;/p&gt;&#10;&lt;p&gt;send_headers_frame&lt;/p&gt;&#10;&lt;p&gt;send_push_promise_frame&lt;/p&gt;&#10;&lt;p&gt;send_rst_stream_frame&lt;/p&gt;&#10;&lt;p&gt;send_settings_frame&lt;/p&gt;&#10;&lt;p&gt;send_ping_frame&lt;/p&gt;&#10;&lt;p&gt;send_goaway_frame&lt;/p&gt;&#10;&lt;p&gt;send_window_update_frame&lt;/p&gt;&#10;&lt;p&gt;比较简单，就是检查字段合法性，序列化，然后发送。&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;4. trafficserver/proxy/http2/Http2Stream.h, Http2Stream.cc&#10; &lt;div id="4--trafficserverproxyhttp2http2streamh-http2streamcc" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#4--trafficserverproxyhttp2http2streamh-http2streamcc" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;对应实现HTTP2 的Stream，重要的成员变量有：&lt;/p&gt;&#10;&lt;p&gt;Http2StreamState _state;//实现IDLE，OPEN，RESERVED，HALF_CLOSE等的切换。&lt;/p&gt;&#10;&lt;p&gt;DependencyTree::Node *priority_node;// Priority Tree中的节点指针。&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;5. trafficserver/proxy/http2/Http2DependencyTree.h, Http2DependencyTree.cc&#10; &lt;div id="5--trafficserverproxyhttp2http2dependencytreeh-http2dependencytreecc" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#5--trafficserverproxyhttp2http2dependencytreeh-http2dependencytreecc" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;Http2DependencyTree::Node 表示一个Stream，成员变量有：&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;actived&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//是否有输出数据&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;queued&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//是否在 actived 队列中&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//queue中的节点按照这个 point 做优先级排序&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Node&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//父节点&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;DLL&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//子节点的双列表&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;PriorityQueueEntry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt; &lt;span class="o"&gt;*&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// &#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;PriorityQueue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt; &lt;span class="o"&gt;*&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;//有输出数据的所有子节点的队列，按point 优先级降序排列&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Http2Stream&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Http2DependencyTree 中有个 Node * root 指向 树的根节点。&lt;/p&gt;&#10;&lt;p&gt;Http2DependencyTree的主要方法有：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;Node *find(uint32_t id);&lt;br&gt;&#10;DFS 递归遍历树，查找一个Stream。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;Node *add(uint32_t parent_id, uint32_t id, uint32_t weight, bool exclusive, T t);&#10;就是插入 parent 的 children 链表中，兼做 exclusive 处理。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;void remove(Node *node);&#10;从parent 的 queue 中移除自己，把自己的 queue 全转给 parent，把自己的 children 全转给 parent&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;void reprioritize(uint32_t new_parent_id, uint32_t id, bool exclusive);&#10;重排优先级，就是移动节点&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;Node *top();&#10;返回整个树中，point 最高的叶子节点。递归实现。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;void activate(Node *node);&#10;往上遍历，如果当前节点没有 在 parent 的 queue中，加入&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;void deactivate(Node *node, uint32_t sent);&#10;从parent 的queue中去除自己。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;void update(Node *node, uint32_t sent);&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;这里使用 Weighted Fair Queue (WFQ) Scheduling 来调度 Stream 之间的优先级。&lt;/p&gt;&#10;&lt;p&gt;Http2ConnectionState::send_data_frames_depends_on_priority()&#10;中，是直接取了 树的 top() 节点，&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;6. trafficserver/proxy/http2/HPACK.h, HPACK.cc&#10; &lt;div id="6--trafficserverproxyhttp2hpackh-hpackcc" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#6--trafficserverproxyhttp2hpackh-hpackcc" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;实现 HPACK 压缩/解压缩&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;7. trafficserver/proxy/http2/HuffmanCodec.h, HuffmanCodec.cc&#10; &lt;div id="7--trafficserverproxyhttp2huffmancodech-huffmancodeccc" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#7--trafficserverproxyhttp2huffmancodech-huffmancodeccc" aria-label="锚点"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;实现静态的 Huffman 表，接口简单，只有4个函数，，&lt;/p&gt;&#10;&lt;p&gt;是实现成 二叉树，相比proxygen估计效率会低一些。&lt;/p&gt;</content:encoded></item></channel></rss>