??xml version="1.0" encoding="utf-8" standalone="yes"?>欧美freesex交免费视频,亚洲成色精品,中文字幕视频免费在线观看http://www.aygfsteel.com/jiangshachina/category/55119.htmla cup of Java, cheers!zh-cnThu, 13 Oct 2016 20:45:10 GMTThu, 13 Oct 2016 20:45:10 GMT60探烦(ch)HTTP/2: 的状??http://www.aygfsteel.com/jiangshachina/archive/2016/10/08/431871.htmlJohn JiangJohn JiangSat, 08 Oct 2016 13:17:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2016/10/08/431871.htmlhttp://www.aygfsteel.com/jiangshachina/comments/431871.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2016/10/08/431871.html#Feedback0http://www.aygfsteel.com/jiangshachina/comments/commentRss/431871.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/431871.html
探烦(ch)HTTP/2: 的状?/span>
探烦(ch)HTTP/2pd的第四篇文章Q解M(jin)HTTP/2的状态,以及(qing)状态之间的转化?2016.10.09最后更?

1. 概述
    HTTP/2的流(Stream)是有状态的。当客户端或服务器端在用某个流d送或接收特定?Frame)或包含特定标{?Flag)的Ӟ?x)引h的状态的转化?a >HTTP 2协议定义的流状态,如下所C:(x)
                         +--------+
                 send PP |        | recv PP
                
,--------|  idle  |--------.
               /         |        |         \
              v          +--------+          v
       +----------+          |           +----------+
       |          |          | send H /  |          |
,------| reserved |          | recv H    | reserved |------.
|      | (local)  |          |           | (remote) |      |
|      +----------+          v           +----------+      |
|          |             +--------+             |          |
|          |     recv ES |        | send ES     |          |
|   send H |     ,-------|  open  |-------.     | recv H   |
|          |    /        |        |        \    |          |
|          v   v         +--------+         v   v          |
|      +----------+          |           +----------+      |
|      |   half   |          |           |   half   |      |
|      |  closed  |          | send R /  |  closed  |      |
|      | (remote) |          | recv R    | (local)  |      |
|      +----------+          |           +----------+      |
|           |                |                 |           |
|           | send ES /      |       recv ES / |           |
|           | send R /       v        send R / |           |
|           | recv R     +--------+   recv R   |           |
| send R /  `----------->|        |<-----------'  send R / |
| recv R                 | closed |               recv R   |
`----------------------->|        |<----------------------'
                         +--------+

   send:   endpoint sends this frame
   recv:   endpoint receives this frame

   H:  HEADERS frame (with implied CONTINUATIONs)
   PP: PUSH_PROMISE frame (with implied CONTINUATIONs)
   ES: END_STREAM flag
   R:  RST_STREAM frame
    ȝ_(d)HTTP/2为流的整个生命周期定义了(jin)7U状态:(x)idleQreserved (local)Qreserved (remote)QopenQhalf closed (local)Qhalf closed (remote)和closed。当一端发送或接收头部?׃个HEADERS/PUSH_PROMISE帧和紧随它的零到多个CONTINUATION帧组成的集合)或RST_STREAM帧,或包含有END_STREAM标签的(HEADERS和DATA)之后Q将改变?gu)的状态?/span>
    的状态基于各端自q视角。由于的传输会(x)有网lgq,在同一时刻Q不同端认ؓ(f)的流的状态可能是不同的。比如,当发送端使用一个处于idle状态的发送一个不包含END_STREAM标签的HEADERS帧之后会(x)立即认ؓ(f)该流处于open状态,但此时接收端未得到该HEADERS帧,所以在那一时刻Q接收端依然认ؓ(f)该流的状态是idle?/span>

2. idle
    所有的在创徏之初都处于idle状态。处于idle状态的,只允许被用于发送HEADERS帧,但可以被用于接收HEADERS和PRIORITY帧。在一端用该状态的发送或接收HEADERS帧之后,该端?x)认为此的状态{变(sh)ؓ(f)open。接收PRIORITY帧不?x)改变流的状态?/span>
    一个idle状态的可被另一个流通过发?接收PUSH_PROMISE帧保留着Q其在来被用于服务器端推送。被保留的流的状态则从idle变(sh)ؓ(f)reserved (local/remote)?/span>

3. open
    处于open状态的可被用于发送Q何类型的帧。用该状态的去发?接收包含有END_STREAM标签的(HEADERS和DATA)之后Q会(x)使该的状态变成half closed (local/remote)。用open状态的发送或接收RST_STREAM帧之后,则会(x)使它的状态{变(sh)ؓ(f)closed?/span>

4. half closed (local/remote)
    状态half closed (local)与half closed (remote)中的local与remote的区别,完全是基于各端自q视角。对于同一个流的两端,如果一端认个流的状态是half closed (local)Q那么另一端只能认个流的状态是half closed (remote)?/span>
    处于half closed (local)状态的只能被用于发送WINDOW_UPDATEQPRIORITY和RST_STREAM帧,但可以被用于接收Mcd的。相对应圎ͼ处于half closed (remote)状态的只能被用于接收WINDOW_UPDATEQPRIORITY和RST_STREAM帧,但可以被用于发送Q何类型的帧?/span>

5. reserved (local/remote)
    与half closed (local/remote)状态相|reserved (local/remote)状态中的local与remote也是Z两端各自的视角。更具体的是Q服务器端发送PUSH_PROMISE一个idle状态的保留着以用于未来的推送,q视q个被保留的的状态ؓ(f)reserved (local)Q而客L(fng)则视q个的状态ؓ(f)reserved (remote)?/span>
    服务器端使用reserved (local)状态的向客户端发送HEADERS帧。该HEADERS帧就是服务器端推?Server Push)中被推送的响应的头部。当发送了(jin)HEADERS帧之后,服务器端视该流的状态ؓ(f)half closed (remote)?/span>
相应圎ͼ客户端通过reserved (remote)状态的接收到服务器端推送的响应的头部,然后?x)视该流的状态ؓ(f)half closed (local)?/span>
    扩展一下,服务器端推送中被保留的的状态在变(sh)ؓ(f)half closed(local/remote)之后才可能被用于接收/发送被推送的响应的体部,也就是DATA帧?/span>

6. closed
    当一端用一个流发送或接收到RST_STREAM帧,或通过状态ؓ(f)half closed (local/remote)的流接收/发送包含有END_STREAM标签的之后Q都?x)视q个的状态ؓ(f)closed?/span>
    closed状态预C着的l结Q处于该状态的将只能发送或接收PRIORITY帧。但有一个特例。即Q如果通过使用half closed (local/remote)状态的去接收或发送包含有END_STREAM标签的(HEADERS或DATA)Q以使该的状态变?sh)closedQ那么在此之后的较短旉内,仍然可以接收WINDOW_UPDATE或RST_STREAM帧?/span>


John Jiang 2016-10-08 21:17 发表评论
]]>
探烦(ch)HTTP/2: HPACK协议q??http://www.aygfsteel.com/jiangshachina/archive/2016/09/24/431837.htmlJohn JiangJohn JiangSat, 24 Sep 2016 12:29:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2016/09/24/431837.htmlhttp://www.aygfsteel.com/jiangshachina/comments/431837.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2016/09/24/431837.html#Feedback0http://www.aygfsteel.com/jiangshachina/comments/commentRss/431837.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/431837.html
探烦(ch)HTTP/2: HPACK协议q?/span>
探烦(ch)HTTP/2pd的第一文章已l介l了(jin)HTTP 2协议Q本文则简q用于HTTP/2头部压羃?a >HPACK协议?2016.10.01最后更?

1. 基本原理
    HPACK头部压羃的基本原理就是用烦(ch)引表?a >Huffman~码。在压羃(~码)与解?解码)q程Q可指定的头部字段(包含字段名与字段?存储在烦(ch)引表中。烦(ch)引表中的每一个条目由索引(一个整?Q字D名和字D值组成。对于存在烦(ch)引表中的头部字段Q在~码时可以仅使用索引作ؓ(f)该字D늚代表Q在解码旉过该烦(ch)引从表中查找出对应的字段。对于其它的字符Ԍ则可以用Huffman~码q行压羃?br /> 1.1 索引?/strong>
    索引表由?rn)态表与动态表l成。静(rn)态表由HPACK协议预定义的61个常用的头部字段l成Q其中大部分字段的gؓ(f)I。静(rn)态表是只ȝQ其中的条目?qing)其位置均不可更攏VHPACK协议中的附录A列出?jin)全部的静(rn)态表条目。动态表也由一pd头部字段l成Q但其中的元素不固定Q在实际操作中可以插入新的条目,也允许删除已有的条目?br />     HPACK协议要求?rn)态表与动态表合ƈ在同一个存储空间中Q其中静(rn)态表|于前部Q动态表紧随其后。那么在整个索引表空间中Q动态表的第一个条目的索引是62。动态表的维护原则是先进先出(FIFO)。当向动态表中增加条目时Q将L从第62位插入,原有的条目将全部向右Ud一个位|。当从动态表中删除条目时Q将L从最后一位进行删除?br />     虽说Q协议要求将?rn)态表与动态表合ƈ在一P但这只是逻辑上的要求。只要动态表的烦(ch)引是?2开始,那么各个实现可以Ҏ(gu)自己的喜好自由地使用存储数据l构。比如,可以静(rn)态表单独攑֜一个不可变的数l中Q而动态表由另一个链表进行存储,q样可能?x)便于插入和删除条目。只不过Q这个链表中元素的下标与动态表中条目的索引之间相差62?br />     (动?索引表中的条目允?dng)R复?br /> 1.2 Huffman~码
    Huffman~码是一U用于无损数据压~的权\径编码算法。在使用该算法时Q需要一张所有被~码字符的权?出现频率)代码表。在对大量的HTTP头部hq行l计之后Q得Z(jin)一份适用于HPACK的Huffman代码表,由协议中?a >附录B列出?br />
    必须注意的是QHPACK协议q不要求该协议的实现一定要使用索引表,即便某个字段已经存在于烦(ch)引表中了(jin)。而且也不要求一定要对字W串实施Huffman压羃。也是_(d)理论上,在编码时可以不对头部字段q行M形式的压~,而只需所有的字符转化成字节Ş式?br />
2. 基本数据cd表示?/span>
    HPACK协议使用的基本数据类型只有两U:(x)整数Q字W串。该协议使用整数去表C烦(ch)引和字符串的长度。头部字D名和g出现的数字,只会(x)被当作字W串q行处理?br /> 2.1 整数表示?/strong>
    HPACK在表C整数时q不是把它简单的转换成二q制形式。因为HPACK希望每一个整数的表示能够从某?比特位字?octetQ下文将其简写ؓ(f)"字节")中的M一个比特位开始,但L要在某个字节的最后一个比特位l束。比如表C?27Q让它从字节的第一个比特位开始填充,肯定?x)在最后一个比特位l束Q如下图所C:(x)
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
+---+---+---+---+---+---+---+---+
如果W一个比特位被其它值占???"代表)Q只能从W二个比特位开始填充呢Q结果依然只需要一个字节,如下所C:(x)
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| ? | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
+---+---+---+---+---+---+---+---+
但如果是从第三个比特位开始填充呢Q这时会(x)发现一个字节已l不够了(jin)Q必要W二个字节。但能否表示成如下Ş式呢Q?br />
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| ? | ? | 1 | 1 | 1 | 1 | 1 | 1 |
+---+---+---+-------------------+
| 1 | ? | ? | ? | ? | ? | ? | ? |
+---+---+---+---+---+---+---+---+
q显然不W合HPACK协议的要求,因ؓ(f)它希望能够在某个字节的最后一个比特位l束q个表示。ؓ(f)辑ֈq一目的QHPACK协议设计Z(jin)一U如下图所C的表示法,
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| ? | ? | 1 | 1   1   1   1   1 |
+---+---+---+-------------------+
| 1 |    Value-(2^N-1) LSB      |
+---+---------------------------+
               ...
+---+---------------------------+
| 0 |    Value-(2^N-1) MSB      |
+---+---------------------------+
W一个字节中能够被用来填充整数表CZ的比特位?上图中的?)被称为prefix。下面是该表C法的Java语言实现Q?br />
public void encodeInteger(int value, int prefix) {
    
if (value >> prefix <= 0) {
        printBinary(value);
    } 
else {
        
int number = (1 << prefix) - 1;
        printBinary(number);
        
for (value -= number; value >= 128; value /= 128) {
            printBinary(value 
% 128 + 128);
        }
        printBinary(value);
    }
}

private void printBinary(int value) {
    System.out.println(String.format(
"%8s", Integer.toBinaryString(value)).replace(" ""0"));
}
Ҏ(gu)上述法可知Q当prefix?Ӟ127的表C法如下图所C:(x)
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| ? | ? | 1 | 1 | 1 | 1 | 1 | 1 |
+---+---+---+-------------------+
| 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
+---+---+---+-------------------+
2.2 字符串表C法
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| H |    String Length (7+)     |
+---+---------------------------+
|  String Data (Length octets)  |
+-------------------------------+
HPACK协议使用上图展示的表C法Q它׃部分l成Q?br /> [1]Huffman标志Q表C字符串是否ؓ(f)Huffman~码Q占用一个比特位?br /> [2]字符串长度,一个?.1节所q方法表C的整数Q其中prefix??br /> [3]字符串倹{若Huffman标志?Q该值就是原始字W串的字节,否则该值是lHuffman~码q的数据。由于经Huffman~码q的数据q不L能在一个字节的最后一个比特位处结束,所以可能会(x)使用EOS(end-of-string)W号q行填充?br />
3. 头部字段表示?/span>
    有了(jin)W?节介l的基本数据cd的表C法作ؓ(f)基础Q现在就可以阐述头部字段的表C法?jin)。HPACK协议字D表C法分成3U类型。在表示法开头有一个或若干个比特位用于表示cd?br /> 3.1 已在索引表的头部字段
    cd标识占用1个比特位Qgؓ(f)1。烦(ch)引用prefix?的整数表C法。在解码Ӟ不会(x)更新动态表?br />
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 1 |        Index (7+)         |
+---+---------------------------+
3.2 置入烦(ch)引表的头部字D?/strong>
    cd标识占用2个比特位Qgؓ(f)01。在解码Ӟ?x)向动态表内插入新条目。这U类型又被分成两U情况:(x)
[1]头部字段名已在烦(ch)引表中,字段名烦(ch)引用prefix?的整数表C法Q而字Dg用字W串表示法?br />
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 1 |      Index (6+)       |
+---+---+-----------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+
[2]头部字段名不在烦(ch)引表中,字段名和字段值均使用字符串表C法Q而第一个字节的?个比特位均?填充?br />
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 1 |           0           |
+---+---+-----------------------+
| H |     Name Length (7+)      |
+---+---------------------------+
|  Name String (Length octets)  |
+---+---------------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+
3.2 暂不|入索引表的头部字段
    cd标识占用4个比特位Qgؓ(f)0000。在解码Ӟ不向动态表内插入新条目。这U类型又被分成两U情况:(x)
[1]头部字段名已在烦(ch)引表中,字段名烦(ch)引用prefix?的整数表C法Q而字Dg用字W串表示法?br />
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 |  Index (4+)   |
+---+---+-----------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+
[2]头部字段名不在烦(ch)引表中,字段名和字段值均使用字符串表C法Q而第一个字节的?个比特位均?填充?br />
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 |       0       |
+---+---+-----------------------+
| H |     Name Length (7+)      |
+---+---------------------------+
|  Name String (Length octets)  |
+---+---------------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+---+---------------------------+
3.3 怸|入索引表的头部字段
    cd标识占用4个比特位Qgؓ(f)0001。在解码Ӟ不向动态表内插入新条目。这U类型又被分成两U情况:(x)
[1]头部字段名已在烦(ch)引表中,字段名烦(ch)引用prefix?的整数表C法Q而字Dg用字W串表示法?br />
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 1 |  Index (4+)   |
+---+---+-----------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+
[2]头部字段名不在烦(ch)引表中,字段名和字段值均使用字符串表C法Q而第一个字节的?个比特位均?填充?nbsp;  
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 1 |       0       |
+---+---+-----------------------+
| H |     Name Length (7+)      |
+---+---------------------------+
|  Name String (Length octets)  |
+---+---------------------------+
| H |     Value Length (7+)     |
+---+---------------------------+
| Value String (Length octets)  |
+-------------------------------+
    可以发现Q?.2节与3.3节中的表C法除了(jin)cd标识不同之外Q其它的都完全相同。那么它们的区别是什么呢Q类?000表示的字D在l过多次解码与编码时Q可能会(x)被某个中介者置入烦(ch)引表中。而类?001表示法强调了(jin)该字D|论在M时候都不可|入索引表。类?001可用于表C包含有敏感信息Q如密码Q的字段|以避免对q些D行压~时产生的风险?br />
4. 动态表的管?/span>
    动态表中的条目被认为是有尺寸的Q其计算公式为:(x)字段名的字节长度+字段值的字节长度+32。字D名/值的长度是指它们的原始字节的长度Q而非l过Huffman~码后的字节的长度?br />     动态表的尺寸就是其中所有条目的寸之和。动态表的最大尺寸是有限的,可以通过下面的整数表C法来通知协议的现实去改变动态表的最大尺寸?br />
  0   1   2   3   4   5   6   7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 1 |   Max size (5+)   |
+---+---------------------------+
    当插入新的条目或改变动态表的最大尺寸时Q可能导致已有的一个或多个条目被逐出Q甚x(chng)I整个动态表。将动态表的最大尺寸设|ؓ(f)0是合法的Q实际上Q这是一U常用的清空动态表的途径?/div>

John Jiang 2016-09-24 20:29 发表评论
]]>
探烦(ch)HTTP/2: 初试HTTP/2(?http://www.aygfsteel.com/jiangshachina/archive/2016/09/20/431814.htmlJohn JiangJohn JiangTue, 20 Sep 2016 08:42:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2016/09/20/431814.htmlhttp://www.aygfsteel.com/jiangshachina/comments/431814.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2016/09/20/431814.html#Feedback1http://www.aygfsteel.com/jiangshachina/comments/commentRss/431814.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/431814.html
探烦(ch)HTTP/2: 初试HTTP/2
目前支持HTTP/2的服务器端与客户端实现已有不,探烦(ch)HTTP/2pd的第二篇分别以Jetty和curl作ؓ(f)服务器端和客L(fng)Q描qC(jin)HTTP/2试环境的搭E。本文还用这个测试环境去展示Jetty在实现HTTP/2时的一个局限和一个Bug?2016.09.22最后更?

1. HTTP/2的实?/span>
    目前已经有众多的服务器端和客L(fng)实现?jin)对HTTP/2的支持。在服务器端Q著名的Apache httpd?.4.17版,Nginx?.9.5版,开始支持HTTP/2。在客户端,L的浏览器Q如ChromeQFireFox和IEQ的最新版均支持HTTP/2Q但它们都只支持q行在TLS上的HTTP/2(即h2)。用Java语言实现的,则有Jetty和NettyQ它们都实现?jin)服务器端和客户端。此处有一份HTTP/2实现的列表:(x)https://github.com/http2/http2-spec/wiki/Implementations
    另外Q还有一些工h持对HTTP/2的分析与调试Q如curl和W(xu)ireShark。这里也有一份此cdL(fng)列表Q?a >https://github.com/http2/http2-spec/wiki/Tools

2. 服务器端
    作ؓ(f)JavaE序员,选用一ƾ用Java语言~写的开源HTTP/2服务器端实现g是很自然的结果。实际上Q在日后的研I中Q我们也需要查看服务器端的源代码。这对于深入地理解HTTP/2Qƈ发现实现中可能的问题Q具有现实意义?/span>
    本文选择Jetty的最新版?.3.11作ؓ(f)服务器端。Jetty是一个成熟的Servlet容器Q这为开发Web应用E序提供?jin)极大便利。而本文第1节中提到的Netty是一个传输层框架Q它专注于网l程序。可以用Nettyd发一个Servlet容器Q但q显然不如直接用Jetty方便?/span>
    安装和配|Jetty是一件很Ҏ(gu)的事情,具体q程如下所C?/span>
    假设此时已经下蝲q解压好?jin)Jetty 9.3.11的压~文Ӟ目录名ؓ(f)jetty-9.3.11。在其中创徏一个test-base子目录,作ؓ(f)要创徏的Jetty Base的目录?/span>
$ cd jetty-9.3.11
$ mkdir test-base
$ cd test-base
在创建BaseӞ加入支持httpQhttpsQhttp2(h2)Qhttp2c(h2c)和deploy的模块?/span>
$ java -jar ../start.jar --add-to-startd=http,https,http2,http2c,deploy

ALERT: There are enabled module(s) with licenses.
The following 1 module(s):
 + contains software not provided by the Eclipse Foundation!
 + contains software not covered by the Eclipse Public License!
 + has not been audited for compliance with its license

 Module: alpn
  + ALPN is a hosted at github under the GPL v2 with ClassPath Exception.
  + ALPN replaces/modifies OpenJDK classes in the java.sun.security.ssl package.
  + http://github.com/jetty-project/jetty-alpn
  + http://openjdk.java.net/legal/gplv2+ce.html

Proceed (y/N)? y
INFO: server          initialised (transitively) in ${jetty.base}\start.d\server.ini
INFO: http            initialised in ${jetty.base}\start.d\http.ini
INFO: ssl             initialised (transitively) in ${jetty.base}\start.d\ssl.ini
INFO: alpn            initialised (transitively) in ${jetty.base}\start.d\alpn.ini
INFO: http2c          initialised in ${jetty.base}\start.d\http2c.ini
INFO: https           initialised in ${jetty.base}\start.d\https.ini
INFO: deploy          initialised in ${jetty.base}\start.d\deploy.ini
INFO: http2           initialised in ${jetty.base}\start.d\http2.ini
DOWNLOAD: http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.5.v20150921/alpn-boot-8.1.5.v20150921.jar to ${jetty.base}\lib\alpn\alpn-boot-8.1.5.v20150921.jar
DOWNLOAD: https://raw.githubusercontent.com/eclipse/jetty.project/master/jetty-server/src/test/config/etc/keystore?id=master to ${jetty.base}\etc\keystore
MKDIR: ${jetty.base}\webapps
INFO: Base directory was modified
    注意Q在上述q程中,?x)根据当前环境变量中使用的Java版本(此处?.8.0_60)M载一个对应的TLS-ALPN实现jar文g(此处为alpn-boot-8.1.5.v20150921.jar)Q该jar?x)用于对h2的支持。当启动JettyӞ该jar?x)被Java的Bootstrap class loader加蝲到类路径中?/span>
    创徏一个最单的Web应用Q它在根目录下包含一个文本文件indexQ内容ؓ(f)"HTTP/2 Test"?/span>再包含一个简单的ServletQ代码如下:(x)
package test;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class TestServlet extends HttpServlet {

    
private static final long serialVersionUID = 5222793251610509039L;

    @Override
    
public void doGet(HttpServletRequest request, HttpServletResponse response)
            
throws ServletException, IOException {
        response.getWriter().println("Test");
    }

    @Override
    
public void doPost(HttpServletRequest request, HttpServletResponse response)
            
throws ServletException, IOException {
        doGet(request, response);
    }
}
web.xml主要是定义了(jin)一个ServletQ具体内容如下:(x)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    metadata-complete="false" version="3.1">

    
<welcome-file-list>
        
<welcome-file>index</welcome-file>
    
</welcome-file-list>

    
<servlet>
        
<servlet-name>test</servlet-name>
        
<servlet-class>test.TestServlet</servlet-class>
    
</servlet>
    
<servlet-mapping>
        
<servlet-name>test</servlet-name>
        
<url-pattern>/test/*</url-pattern>
    
</servlet-mapping>
</web-app>
该应用的部v路径为jetty-9.3.11/test-base/webapps/test.war。在该WAR文g所在的目录下,创徏一个test.xmlQ其内容如下所C:(x)
<?xml version="1.0"  encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">

<Configure class="org.eclipse.jetty.webapp.WebAppContext">
  
<Set name="contextPath">/</Set>
  
<Set name="war"><SystemProperty name="jetty.base" default="."/>/webapps/test.war</Set>
</Configure>
启动Jetty服务器,使用默认的HTTP和HTTPS端口Q分别ؓ(f)8080?443?/span>
$ java -jar ../start.jar
2016-09-15 21:15:51.190:INFO:oejs.Server:main: jetty-9.3.11.v20160721
2016-09-15 21:15:51.237:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///D:/http2/jetty/jetty-9.3.11/test-base/webapps/] at interval 1
2016-09-15 21:15:52.251:INFO:oejw.StandardDescriptorProcessor:main: NO JSP Support for /test.war, did not find org.eclipse.jetty.jsp.JettyJspServlet
2016-09-15 21:15:52.313:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@4520ebad{/test.war,file:///D:/http2/jetty/jetty-9.3.11/test-base/webapps/test.war/,AVAILABLE}{D:\http2\jetty\jetty-9.3.11\test-base\webapps\test.war}
2016-09-15 21:15:52.391:INFO:oejw.StandardDescriptorProcessor:main: NO JSP Support for /, did not find org.eclipse.jetty.jsp.JettyJspServlet
2016-09-15 21:15:52.391:INFO:oejsh.ContextHandler:main: Started o.e.j.w.WebAppContext@711f39f9{/,file:///D:/http2/jetty/jetty-9.3.11/test-base/webapps/test.war/,AVAILABLE}{/test.war}
2016-09-15 21:15:52.532:INFO:oejs.AbstractConnector:main: Started ServerConnector@1b68ddbd{HTTP/1.1,[http/1.1, h2c, h2c-17, h2c-16, h2c-15, h2c-14]}{0.0.0.0:8080}
2016-09-15 21:15:52.735:INFO:oejus.SslContextFactory:main: x509=X509@e320068(jetty,h=[jetty.eclipse.org],w=[]) for SslContextFactory@1f57539(file:///D:/http2/jetty/jetty-9.3.11/test-base/etc/keystore,file:///D:/http2/jetty/jetty-9.3.11/test-base/etc/keystore)
2016-09-15 21:15:52.735:INFO:oejus.SslContextFactory:main: x509=X509@76f2b07d(mykey,h=[],w=[]) for SslContextFactory@1f57539(file:///D:/http2/jetty/jetty-9.3.11/test-base/etc/keystore,file:///D:/http2/jetty/jetty-9.3.11/test-base/etc/keystore)
2016-09-15 21:15:53.234:INFO:oejs.AbstractConnector:main: Started ServerConnector@4b168fa9{SSL,[ssl, alpn, h2, h2-17, h2-16, h2-15, h2-14, http/1.1]}{0.0.0.0:8443}
2016-09-15 21:15:53.249:INFO:oejs.Server:main: Started @3940ms
    Ҏ(gu)上述日志可知QJetty启用?jin)Web应用test.warQ还启动?jin)两个ServerConnectorQ一个支持h2cQ另一个支持h2。值得注意的是Q这两个ServerConnectorq分别支持h2c-17, h2c-16, h2c-15, h2c-14和h2-17, h2-16, h2-15, h2-14。这是因为,HTTP/2在正式发布之前,先后发布?8个草案,其编号ؓ(f)00-17。所以,q里的h2c-XX和h2-XX指的是WXX可案?/span>

3. 客户?/span>
    其实最方便的客L(fng)是览器了(jin)。只要用的FireFox或Chrome版本不是太老,肯定都已l支持了(jin)HTTP/2Q而且q一功能是默认打开的。也是_(d)当用FireFox去访问前面所部v的Web应用Ӟ是在用HTTP/2Q但你不?x)感觉到q种变化。用FireFox提供的Developer Tools中的Network工具查看服务器端的响应,?x)发现HTTP版本为HTTP/2.0。但此处希望q个客户端能够提供更Z富的与服务器端进行交互的功能Q那么浏览器ƈ不合适了(jin)?br />    Jetty也实C(jin)支持HTTP/2的客L(fng)Q但q个客户端是一个APIQ需要编写程序去讉KHTTP/2服务器端。而且Q目前该API的设计抽象层ơ较低,需要应用程序员对HTTP/2协议Q比如各UQ有较深入的?jin)解。这对于初涉HTTP/2的开发者来_(d)昄很不合适。本文选择使用C语言~写的一个工P其实也是HTTP/2的客L(fng)实现之一Qcurl?/span>
    curl在支持HTTP/2Ӟ实际上是使用?jin)nghttp2的C库,所以需要先安装nghttp2。另外,Z(jin)让curl支持h2Q就必须要有TLS-ALPN的支持。那么,一般地q需要安装OpenSSL 1.0.2+?/span>
    |络上关于在Linux下安装支持HTTP/2的curl的资源有很多Q过Eƈ不难Q但有点儿繁Q要安装的依赖比较多Q本文就不赘qC(jin)。如果是使用WindowsQ笔者比较推荐通过Cygwin来安装和使用curl。在Windows中安装Cygwin非常单,在Cygwin中执行各U命令时Q感觉上如同在使用LinuxQ尽它q不是一个虚拟机。通过Cygwin安装curlQ它?x)自动地安装所需的各U依赖程序和库?/span>
    在笔者的机器上,通过查看curl的版本会(x)出现如下信息Q?/span>
curl 7.50.2 (x86_64-unknown-cygwin) libcurl/7.50.2 OpenSSL/1.0.2h zlib/1.2.8 libidn/1.29 libpsl/0.14.0 (+libidn/1.29) libssh2/1.7.0 nghttp2/1.14.0
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: Debug IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets Metalink PSL
׃可知Q笔者用的curl版本?.50.2Qnghttp2版本?.14.0Q而OpenSSL版本?.0.2h?/span>

4. W一ơ尝?/span>
    在第一ơ尝试中Q只需要简单地讉KW?节中部v的Web应用中的?rn)态文本文件indexQ以感受下h2cQ完整命令如下:(x)
$ curl -v --http2 http://localhost:8080/index
在输Z包含有如下的内容Q?/span>
...
> GET /index HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.50.2
> Accept: */*
> Connection: Upgrade, HTTP2-Settings
> Upgrade: h2c
> HTTP2-Settings: AAMAAABkAAQAAP__
>
...
< HTTP/1.1 101 Switching Protocols
* Received 101
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
...
< HTTP/2 200
< server: Jetty(9.3.11.v20160721)
< last-modified: Wed, 14 Sep 2016 12:52:32 GMT
< content-length: 11
< accept-ranges: bytes
<
...
HTTP/2 Test
">"是客L(fng)发送的hQ?<"是服务器端发送的响应Q?*"是curl对当前过E的说明?/span>l合本系?a href="http://www.aygfsteel.com/jiangshachina/archive/2016/09/19/431811.html">W一文?/a>中所q的HTTP 2协议Q可以有以下的基本理解?/span>
[1]客户端发起了(jin)一个HTTP/1.1的请求,其中携带有Upgrade头部Q要求服务器端升U到HTTP/2(h2c)?/span>
> GET /index HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.50.2
> Accept: */*
> Connection: Upgrade, HTTP2-Settings
> Upgrade: h2c
> HTTP2-Settings: AAMAAABkAAQAAP__
>
[2]服务器端同意升Q返回响?101 Switching Protocols"Q然后客L(fng)收到?01响应QHTTP/2q接q行认?/span>
< HTTP/1.1 101 Switching Protocols
* Received 101
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
[3]服务器端响应最l结果。状态行中出现的HTTP版本为HTTP/2Q状态代码ؓ(f)200Q且后面没有跟着"OK"。最后输Z(jin)index文g的内?HTTP/2 Test"?/span>
< HTTP/2 200
< server: Jetty(9.3.11.v20160721)
< last-modified: Wed, 14 Sep 2016 12:52:32 GMT
< content-length: 11
< accept-ranges: bytes
<
...
HTTP/2 Test

5. 一个局?/span>
    q次Q在发v的请求中包含体部Q命令如下:(x)
$ curl -v --http2 -d "body" http://localhost:8080/index
在输Z包含有如下的内容Q?/span>
...
> POST /index HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.50.2
> Accept: */*
> Connection: Upgrade, HTTP2-Settings
> Upgrade: h2c
> HTTP2-Settings: AAMAAABkAAQAAP__
> Content-Length: 4
> Content-Type: application/x-www-form-urlencoded
>
...
< HTTP/1.1 200 OK
< Last-Modified: Wed, 14 Sep 2016 12:52:32 GMT
< Accept-Ranges: bytes
< Content-Length: 11
...
HTTP/2 Test
    和第4节中的输?gu)行比较,会(x)发现缺?jin)"101 Switching Protocols"那一D,而且最l响应状态行中出现的HTTP版本是HTTP/1.1。这p明服务器端不同意升Q后面(h)l用HTTP/1.1。刚刚部|的Jetty未做M改变怎么?x)突然不支持HTTP/2?jin)呢Q或者这是curl的问题?其实Q?/span>q是因ؓ(f)Jetty服务器端在实现h2c时不支持h中包含体部。另外,Apache httpd也有同样的问题。如果是使用h2Q则没有q个限制。这背后的原因超Z(jin)本文的范_(d)不作表述?/span>

6. 一个Bug
    在这ơ尝试中Q测试一下两端对100-continue的支持。如果请求中使用?jin)头?Expect: 100-continue"Q那么正常地该请求要有体部。但׃在第5节中介绍的问题,此时不能再用h2cQ而只能用h2。另外,q次不访问静(rn)态文Ӟ而是讉KServlet(此处?test)。完整命令如下:(x)
$ curl -vk --http2 -H "Expect: 100-continue" -d "body" https://localhost:8443/test
在输出的最后出C(jin)如下信息Q?/span>
curl: (92) HTTP/2 stream 1 was not closed cleanly: CANCEL (err 8)
q其实是Jetty的一?a >BugQ正在开发中?.3.12已经修复?jin)它?/span>

7. 结
    HTTP/2依然是新潮的技术,对各家的实现Q无论是服务器端Q客L(fng)Q还是分析工P都要持有一份怀疑态度。这些实现和工具都是E序Q都有可能存在bug。而且协议对许多细节没有作?gu)定,各家都?x)发挥自己的想像力。比如,Apache httpd和Jetty在实现服务器端推送时Q其方式׃相同?br />    在开发自qHTTP/2实现或应用的时候,需要同时用已有的不同服务器端和客L(fng)去部|多套测试环境进行对比分析?br />


John Jiang 2016-09-20 16:42 发表评论
]]>
探烦(ch)HTTP/2: HTTP 2协议q??http://www.aygfsteel.com/jiangshachina/archive/2016/09/19/431811.htmlJohn JiangJohn JiangMon, 19 Sep 2016 03:36:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2016/09/19/431811.htmlhttp://www.aygfsteel.com/jiangshachina/comments/431811.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2016/09/19/431811.html#Feedback0http://www.aygfsteel.com/jiangshachina/comments/commentRss/431811.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/431811.html
探烦(ch)HTTP/2: HTTP/2协议q?/span>
HTTP/2的协议包含着两个RFCQHypertext Transfer Protocol Version 2 (RFC7540)Q即HTTP/2QHPACK: Header Compression for HTTP/2 (RFC7541)Q即HPACK。RFC7540描述?jin)HTTP/2的语义,RFC7541则描qC(jin)用于HTTP/2的头部压~的格式。本文只涉及(qing)HTTP/2协议Q本pd的后l文章将?x)涉及(qing)HPACK协议?2016.10.13最后更?

1. HTTP/2要解决的问题
     HTTP/1.0只允许在一个TCPq接中出C个请求。后来的HTTP/1.1虽然引入?jin)请求流水线Q以允许在一个连接中发送多个请求,但这只是部分地解决了(jin)hq发的问题。服务器端在q回响应Ӟq是必须要按照它接收到的h的顺序进行返回。如果排在前面的响应要消耗较长的旉Q那依然?x)对后面的响应的造成dQ亦即线头阻?Head-of-line blocking)。所以,客户端必要使用多条q接d起多个的h以实现ƈ发,q进而减gq。更大的q发?x)增大服务器的负载,也?x)占用更大的网l带宽。另外,头部通常?x)包含有大量的信息,如cookieQ而这也会(x)增加|络传输的开销?/span>
     HTTP/2允许在同一个TCPq接中交错地出现多个h与响应,亦即多工(Multiplex)。同Ӟ它用了(jin)一个高效的~码Ҏ(gu)对头部进行压~。HTTP/2q允许对hq行优先U排序,以便让更为重要的h得以更快的完成,q会(x)q一步提高性能。HTTP/2q改变(sh)(jin)服务器端只能被动地向客户端返回响应的定式Q允许服务器端主动地向客L(fng)推送数据,q就可以减少客户端发赯求的数量?/span>
     MQHTTP/2主要是解x(chng)能问题?/span>

2. 发vHTTP/2
     HTTP/2?x)用与HTTP/1相同的URI schemeQ即http和https。而且实现HTTP/2的服务器端也不会(x)使用不同的端口去分别支持HTTP/1和HTTP/2。这h利于qx(chng)CHTTP/1升到HTTP/2。毕竟目前已部v的绝大部分网l服务都只支持HTTP/1Q当未来它们升到HTTP/2Ӟ如果换用?jin)不同URI scheme或端口,那么肯定?x)对客户端生极大的影响。但是HTTP/2协议行在http和https上的HTTP/2分别定义?jin)两个不同的标识W:(x)h2c和h2。h2c中的"c"指的是cleartextQ即明文。本文后面会(x)使用h2c指代q行在http2?直接使用TCP)的HTTP/2Q而用h2指代q行在https?使用TLS)的HTTP/2?/span>
     那么Q支持HTTP/2的客L(fng)如何知道它所q接的服务器端是否也支持HTTP/2呢?
     对于h2cQ支持HTTP/2的客L(fng)可以在发L(fng)h中用HTTP/1.1的Upgrade头部d试要求服务器升到HTTP/2。该h的格式如下:(x)
GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
HTTP2-Settings是一个经由BASE64~码q的字符Ԍ其原始内Ҏ(gu)客户端将要发送的SETTINGS帧的载荷Q即一些配|参数?/span>
     如果服务器端支持HTTP/2Q它?yu)响?101 Switching Protocols"Q表C可以进行升U。该响应的格式如下:(x)
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c
     如果服务器端不支持HTTP/2Q则?x)忽略Upgradeh头部Q后l依然用HTTP/1.1?/span>
     对于h2Q会(x)使用到协议Transport Layer Security (TLS) Application-Layer Protocol Negotiation Extension (RFC7301)Q即TLS-ALPN。该协议允许客户端和服务器端׃用何U版本的HTTPq行协商。如果TLS-ALPN在现实中q行良好的话Q也许某天还?sh)(x)用该?gu)d商用别的协议?/span>
     当客L(fng)与服务器端都同意使用HTTP/2Ӟ双方都需要各自发Z个连接序a(Connection Preface)以进行最后的认?/span>
     客户端在接收到服务器端的"101 Switching Protocols"响应(针对h2c)或TLSq接的第一个应用数据字?针对h2)之后?x)立卛_?gu)接序a。该序言的开头是"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"(其十六进制Ş式ؓ(f)"0x505249202a20485454502f322e300d0a0d0a534d0d0a0d0a")(1)Q后面必d跟一个SETTINGS帧,哪怕这个是空的?/span>
     服务器端的连接序a则由一个SETTINGS帧构成,该必须是服务器端在HTTP/2q接中发送的W一个。这个SETTINGS帧可以ؓ(f)I,也可以包含一些希望客L(fng)如何与自p行通信的必要配|信息?/span>

3. ?Frame)
     HTTP/2消息使用二进制格?实际~码时用十六进制书?Q相比于文本格式Q这样可以提高消息处理的效率。HTTP/2消息的最单元ؓ(f)帧,它由头部与蝲?Payload)l成。每个的长度必L一个或多个8比特位字?octetQ下文将其简写ؓ(f)"字节")?/span>
     帧头部依ơ包含有如下?个字D:(x)
     长度(Length)Q该字段占用24个比特位Q代表载荷的长度。该长度是一?4位的无符h数?/span>
     cd(Type)Q该字段占用8个比特位Q代表的类型?/span>
     标志(Flags)Q该字段占用8个比特位Q代表所定义的一个或多个标志。ƈ不是所有的帧都定义?jin)标志?/span>
     保留?R)Q该字段占用1个比特位Q其语义未被定义。在d帧时Q该位需要被忽略Q但在发送Ӟ该位需要保持ؓ(f)0(0x0)?/span>
     标识符(Stream Identifier)Q该字段占用31个比特位Q代表该帧所在流的标识符?/span>
     在头部之后,紧接着的就是蝲荗蝲L(fng)l构与内容完全由帧的cd军_Q它的长度也是不定的?br />
     HTTP/2定义?jin)如?0U不同类型的帧?/span>
     DATAQ用于携带一l长度不定的字节。一个或多个DATA可作求或响应的蝲荗?/span>
     HEADERSQ用于开启一个流Qƈ可携带一个头部块片断。头部块指由一个HEADERS/PUSH_PROMISE帧和紧随它的零到多个CONTINUATION帧组成的集合Q因为只有它们才可能携带头部信息。这个集合可被分割成一个或一l字节,q样的字节被UCؓ(f)头部块片断。头部块中各个特定类型的帧必ȝ紧相邻,不能出现其它cd的?/span>
     PRIORITYQ用于指定发送端的流优先U?/span>
     RST_STREAMQ用于立即终止流。当希望取消一个流或发生错误时Q就可发送RST_STREAM帧?/span>
     SETTINGSQ用于携带可以媄(jing)响两端之间通信方式的配|参数。SETTINGS帧定义了(jin)一个ACK标志Q用于指C帧所讄的参数是否已被接收端L(fng)。当收到一个SETTINGS且其中的ACK标志?Ӟ接收端必d可能快的应用其中已被更新的参数?/span>
     PUSH_PROMISEQ用于向接收端通知发送端要创徏的流。当接收端接收到该Ӟ新的尚未被发送端创徏Q但发送端承诺?x)创。该帧用于实现HTTP/2的重要特?服务器端推?Server Push)"?/span>
     PINGQ用于测量发送端与接收端之间的最往q时间。这与用众所周知的ping命o(h)的目的相|是ؓ(f)?jin)测试某个空闲的q接是否q可用?/span>
     GOAWAYQ用于发起对q接的关闭,或触发严重的错误条g。该帧允怸端,在完成对之前已创建的的处理的同Ӟ优雅地停止接收新的流。一端在创徏新的,另一端在发送GOAWAYQ这两者之间天然存在着竞争关系。ؓ(f)?jin)就对这U情况,发送端在发送GOAWAY时会(x)让它携带?该发送端所知晓?接收端最后创建的的标识W,当该GOAWAY被发送之后,发送端会(x)忽视由接收端创徏的Q何一个标识符比该标识W大的流?/span>
     WINDOW_UPDATEQ用于流量控制。该帧的载荷׃个单比特保留位和一?1比特位的无符h数组成。该整数向该帧的接收端指CZ(jin)其向当前量控制H口所能增加传输量的倹{?/span>
     CONTINUATIONQ用于(h)l发送头部块片断。只要同一个流中前面的帧是HEADERSQPUSH_PROMISE或CONTINUATIONQƈ且该帧没有设|END_HEADERS标志Q那么可无限量地发送CONTINUATION帧?/span>
     部分帧,DATAQHEADERS和PUSH_PROMISEQ的载荷中可能包含填?Padding)。填白在业务上没有实际的用处Q它的出现是Z安全目的。比如,可以用它来扰乱实际数据的长度Q以减轻特定的HTTPd?br />
     发送端发送的帧的最大长度要重接收端设定的SETTINGS_MAX_FRAME_SIZE的倹{但该值的范围要介?^14?^24-1个字节之间?/span>

4. ?Stream)
     是用于在客L(fng)与服务器端之间进行传送的通道Q同一个TCPq接中可以同时有多个,如下图所C,
┌────────┐          Connection           ┌────────┐
│        │ ============================= │        │
│        │    --------------------- <-- Stream    │
│        │    ┌─────┐┌─────────┐┌─┐      │        │
│        │    └─────┘└─────────┘└─┘ <-- Frame     │
│        │    ---------------------      │        │
│ Client │                               │ Server │
│        │    ----------                 │        │
│        │    ┌──┐┌────┐                 │        │
│        │    └──┘└────┘                 │        │
│        │    ----------                 │        │
│        │ ============================= │        │
└────────┘                               └────────┘
服务器端和客L(fng)可以交错地向同一个连接中的不同流中传送。可以把一个流看作HTTP/1中的一个连接。客L(fng)与服务器端在同一个流中的交互依然遵@发送请?{待响应模式。两端都可以创徏新的,׃nҎ(gu)创徏的流Q也可以关闭Ҏ(gu)创徏的流。在流中的序是有意义的,接收端会(x)以接收到的顺序去处理帧?br />      每个都有一个标识符Q是一?1比特位的无符合整数。在同一个连接中Q流标识W是唯一的。由客户端创建的的标识Wؓ(f)奇数Q由服务器创建的的标识Wؓ(f)偶数。但标识Wؓ(f)0的流可看作连接,用于q接控制信息Q创建新的流时不可用该标识W。同一个连接中的Q何一个流的标识符都不可重用,即便q个已被关闭了(jin)。对于长旉没有中断的连接,可能?x)出现标识符不够用的情况Q那时就必须强制创徏一个新的连接?br />      HTTP/2协议为流的生命周期定义了(jin)7U状?sup>(2)QidleQreserved(local)Qreserved(remote)QopenQhalf closed(local)Qhalf closed(remote)和closed。当一端接收或发送头部块?帧DATA和HEADERS?标志RST_STREAM后可使流的状态发生{变?/span>
     使用来实现多工׃(x)引v对TCPq接使用的竞争,q会(x)造成的d。基于WINDOW_UPDATE的流量控制方案可以确保相同连接中的流怺之间不会(x)产生破坏性干扰。流量控制可以作用于两个层面Q即单个或整个q接。只有DATA需要遵守流量控Ӟ所有其它的帧所有消耗的I间均不?x)占用流量控制窗口。HTTP/2协议只是定义?jin)WINDOW_UPDATE帧的l构和语义,协议的实现可以选择M适用自己的流量控制算法?/span>
     可以有优先U。客L(fng)在创Z个新的流Ӟ可在HEADERS中指定优先权重。在后箋(hu)M旉Q通过PRIORITY可以改变?gu)的优先U权重。在q发能力有限的情况下Q高权重的帧会(x)被优先传送。权重的值必M??56之间Q默认权重ؓ(f)16?/span>与之间还可以有依赖关p,q种关系?x)组成一依赖关pL(wi)。一个流能够指定自己成ؓ(f)另一个流的子。这一q程Q可以是非排他的Q也可以是排他的。非排他性依赖,是指一个流在将自己变成另一个流的子的q程中,允许另一个流q有别的子流Q即允许有自q兄弟存在。排他性依赖,指在前述q程中,不允许另一个流q有别的子流。如果另一个流已经有子了(jin)Q那么该会(x)把所有潜在的兄弟先变成自己的子,然后再自己成ؓ(f)另一个流的唯一子流。其实,排他性依赖的作用是Z(jin)能够打破已有的关pL(wi)Q在既成的父子节点中插入新的节点。否则,只能为已有节Ҏ(gu)加子节点Q那么关pL(wi)不可能q行重构。所有的在被创建时Q默认成为标识符?x0的流的子。在"服务器端推?中生成的"推?将自动地成为生成该推送流的流的子,光认权重也?6?/span>

5. 消息交换
5.1 h/响应交换
     HTTP/2沿袭?jin)HTTP/1的语义,x(chng)有的h与响应语义均得到?jin)保留,管传递这些语义的语法已经改变?sh)(jin)?/span>
     一个HTTP/2消息由如下几个部分组成:(x)
     [1]仅对于响应消息,可以包含一个携带有1xx响应头部的头部块。该头部块由一个HEADERS帧和紧随它的零到多个CONTINUATION帧组成?/span>
     [2]一个头部块。该头部块由一个HEADERS帧和紧随它的零到多个CONTINUATION帧组成?/span>
     [3]零到多个携带有体?Body)消息的DATA帧。HTTP/1中用的"分块(chunked)"体部不适用于HTTP/2。因Z个体部可由多个DATA帧组成,所以HTTP/2的体部天然就是可分块的?/span>
     [4]一个可能存在的包含着N消息的头部块。该头部块由一个HEADERS帧和紧随它的零到多个CONTINUATION帧组成?br />
     HTTP/2仍然沿用HTTP/1中的头部字段Q但字段名称中的字母必须全部为小写。另外,q将HTTP/1消息开始行(h中的h?/a>与响应中?a >状态行)中的消息Q分解成?jin)若q伪头部字段Q此cdD均以冒?:)开头?/span>
     HTTP/1h行格式ؓ(f)"method request-target HTTP-version"Q对应的HTTP/2伪头部字D|:method=method?path=request-targetQ但HTTP-version无对应字D,默认为HTTP/2?/span>
     HTTP/1状态行格式?HTTP-version status-code reason-phrase"Q对应的HTTP/2伪头部字D|:status=status-code。但HTTP-version无对应字D,默认为HTTP/2Qreason-phrase也无对应字段Q因为可以通过状态代码查扑ֈ其对应的reason-phrase。HTTP/2协议是在量减少冗余消息?/span>
     HTTP/2协议q(sh)ؓ(f)h头部定义?jin)另外两个伪字段Q?/span>
     :schemeQURI中的scheme部分。它可以不仅仅是http或httpsQ因为有时候可能会(x)与非HTTP服务q行交互?/span>
     :authorityQURI中的授权部分。即Qscheme://user:password@host:port/path?query#fragment中的"user:password@host:port"?/span>
     HTTP/2协议8.1.3节中l出一些简单示例,展示?jin)如何将HTTP/1消息对应到HTTP/2消息?/span>
5.2 服务器端推?/span>
     HTTP/2的服务器端推送是传统的请?响应模式的一U特DŞ式。服务器端在收到客户端的h(主请?之后Qؓ(f)?jin)主动向客户端推送更多的内容Q会(x)自动地生成若q新的请?推送请?。服务器向客L(fng)发送的响应中,不仅包含对主h的响?d?Q还包含Ҏ(gu)送请求的响应(推送响??/span>
     客户端可以通过发送包含有SETTINGS_MAX_CONCURRENT_STREAMS参数的SETTINGS帧去用服务器端推送,也可以通过发送RST_STREAM帧去取消已经发v的服务器端推送,但不能发送包含有END_STREAM标志的?br />
(1)"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"中的"PRI"?SM"合v来就?RRISM(镜)"。呵呵,HTTPbis工作l这是想表达什么意思呢 ;-)
(2)本系列的后箋(hu)文章解读?jin)流的状态?br />


John Jiang 2016-09-19 11:36 发表评论
]]>
վ֩ģ壺 | | ͬ| ͤ| | ɽ| | | | | ¡Ң| غ| | | ˷| ϲ| | | | | | ͨ| | Ͻ| | ۳| | ʯ| ½| ζ| | | ƺ| | | | ó| | | | |