HTTP2于2015年2月28日正式通过IETF组织批准发布,正式定稿。有关它的内容可以参考:  HTTP2 概述  http://www.cnblogs.com/ghj1976/p/4552583.html

在HTTP2 的网络通讯中, Frame 是 通讯中的最小传输单位,至少含有一个 Frame header,能够表示它属于哪一个 Stream。一个具体的请求类似如下:

 

 

HTTP/2 帧通用格式:

帧头+负载的比特位通用结构:

帧头为固定的9个字节((24+8+8+1+31)/8=9)呈现,变化的为帧的负载(Frame Payload),负载内容是由帧类型(Type)定义。

 

  • 帧长度Length:无符号的自然数,24个比特表示,仅表示帧负载(Frame Payload)所占用字节数,不包括帧头所占用的9个字节。
    默认大小区间为为0~16,384(2^14),一旦超过默认最大值2^14(16384),发送方将不再允许发送,除非接收到接收方定义的SETTINGS_MAX_FRAME_SIZE(一般此值区间为2^14 ~ 2^24)值的通知。
  • 帧类型Type:8个比特表示,定义了帧负载的具体格式和帧的语义,HTTP/2规范定义了10个帧类型,这里不包括实验类型帧和扩展类型帧
  • 帧的标志位Flags:8个比特表示,服务于具体帧类型,默认值为0x0。
    有一个小技巧需要注意,一般来讲,8个比特可以容纳8个不同的标志,比如,PADDED值为0x8,二进制表示为00001000;END_HEADERS值为0x4,二进制表示为00000100;END_STREAM值为0X1,二进制为00000001。可以同时在一个字节中传达三种标志位,二进制表示为00001101,即0x13。因此,后面的帧结构中,标志位一般会使用8个比特表示,若某位不确定,使用问号?替代,表示此处可能会被设置标志位
  • 帧保留比特为R:在HTTP/2语境下为保留的比特位,固定值为0X0
  • 流标识符Stream Identifier:无符号的31比特表示无符号自然数。0x0值表示为帧仅作用于连接,不隶属于单独的流。

关于帧长度,需要稍加关注: - 0 ~ 2^14(16384)为默认约定长度,所有端点都需要遵守 - 2^14 (16,384) ~ 2^24-1(16,777,215)此区间数值,需要接收方设置SETTINGS_MAX_FRAME_SIZE参数单独赋值 - 一端接收到的帧长度超过设定上限或帧太小,需要发送FRAME_SIZE_ERR错误 - 当帧长错误会影响到整个连接状态时,须以连接错误对待之;比如HEADERS,PUSH_PROMISE,CONTINUATION,SETTINGS,以及帧标识符不该为0的帧等,都需要如此处理 - 任一端都没有义务必须使用完一个帧的所有可用空间 - 大帧可能会导致延迟,针对时间敏感的帧,比如RST_STREAM, WINDOW_UPDATE, PRIORITY,需要快速发送出去,以免延迟导致性能等问题

 

HTTP2 的帧包含下面几种类型,对应上图的Type区域定义。

Frame Type      Code   
DATA            0x0
HEADERS         0x1
PRIORITY        0x2
RST_STREAM      0x3
SETTINGS        0x4
PUSH_PROMISE    0x5
PING            0x6
GOAWAY          0x7
WINDOW_UPDATE   0x8
CONTINUATION    0x9

参考:
HTTP/2 frame format
http://segmentfault.com/a/1190000002586816 

 

帧的标志位(Flags)含义如下图:

图来自: http://search.cpan.org/~crux/Protocol-HTTP2-0.14/lib/Protocol/HTTP2/Frame.pm

 

 

案例:

假设我们要发送 0x12345678,流编号为 10 ,类型为DATA,那么这个Frame的16进制表达就是:

'000004' + '00' + '00' + '0000000A' +   '12345678'

 

HTTP2 的 Header 帧

HTTP2的 HEADER帧的格式如下:

 

对应的字段列表说明如下:

- Pad Length:受制于PADDED标志控制是否显示,8个比特表示填充的字节数。 可选。Flags:PADDED 设置后要求有此字段

- E:一个比特表示流依赖是否专用,可选项,只在流优先级PRIORITY被设置时有效   可选。Flags:PRIORITY 设置后要有此字段

- Stream Dependency:31个比特表示流依赖,只在流优先级PRIORITY被设置时有效     可选。Flags:PRIORITY 设置后要有此字段

- Weight:8个比特(一个字节)表示无符号的自然数流优先级,值范围自然是(1~256),或称之为权重。只在流优先级PRIORITY被设置时有效  这个字段是可选的,并且只在优先级标记设置的情况下才呈现。

- Header Block Fragment:报头块分片

- Padding:填充的字节,受制于PADDED标志控制是否显示,长度由Pad Length字段决定

注意, 只有 Header Block Fragment 是必须的, 其他都看 帧的标志位Flags 是否设置要有。

 

所需标志位:

  • END_STREAM (0x1): 报头块为最后一个,意味着流的结束。

    END_HEADERS (0x4): 此报头帧不需分片,完整的一个帧。后续不再需要CONTINUATION帧帮忙凑齐。若没有此标志的HEADER帧,后续帧必须是以CONTINUATION帧传递在当前的流中,否则接收者需要响应PROTOCOL_ERROR类型的连接错误。
  • PADDED (0x8): 需要填充的标志
  • PRIORITY (0x20): 优先级标志位,控制独立标志位E,流依赖,和流权重。

 

注意事项:

- 其负载为报头块分片,若内容过大,需要借助于CONTINUATION帧继续传输。若流标识符为0x0,结束段需要返回PROTOCOL_ERROR连接异常。HEADERS帧包含优先级信息是为了避免潜在的不同流之间优先级顺序的干扰。

- 其实一般来讲,报文头部不大的情况下,一个HEADERS就可以完成了,特殊情况就是Cookie字段超过16KiB大小,不常见。

 

HTTP2的 CONTINUATION 帧

HTTP2的 CONTINUATION 帧的格式如下:

字段列表:

- Header Block Fragment,用于协助HEADERS/PUSH_PROMISE等单帧无法包含完整的报头剩余部分数据。

 

注意事项:

- 一个HEADERS/PUSH_PROMISE帧后面会跟随零个或多个CONTINUATION,只要上一个帧没有设置END_HEADERS标志位,就不算一个帧完整数据的结束。

- 接收端处理此种情况,从开始的HEADERS/PUSH_PROMISE帧到最后一个包含有END_HEADERS标志位帧结束,合并的数据才算是一份完整数据拷贝

- 在HEADERS/PUSH_PROMISE(没有END_HEADERS标志位)和CONTINUATION帧中间,是不能够掺杂其它帧的,否则需要报PROTOCOL_ERROR错误

标志位: * END_HEADERS(0X4):表示报头块的最后一个帧,否则后面还会跟随CONTINUATION帧。

 

HTTP2的 Data帧

一个或多个DATA帧作为请求、响应内容载体,较为完整的结构如下:

 

 

字段:

  • Pad Length: 一个字节表示填充的字节长度。取决于PADDED标志是否被设置.
  • Data: 这里是应用数据,真正大小需要减去其他字段(比如填充长度和填充内容)长度。
  • * Padding: 填充内容为若干个0x0字节,受PADDED标志控制是否显示。接收端处理时可忽略验证填充内容。若验证,可以对非0x0内容填充回应PROTOCOL_ERROR类型连接异常。

标志位:

  • END_STREAM (0x1): 标志此帧为对应标志流最后一个帧,流进入了半关闭/关闭状态。
  • PADDED (0x8): 负载需要填充,Padding Length + Data + Padding组成。

注意事项:

- 若流标识符为0x0,接收者需要响应PROTOCOL_ERROR连接错误

- DATA帧只能在流处于"open" or "half closed (remote)"状态时被发送出去,否则接收端必须响应一个STREAM_CLOSED的连接错误。若填充长度不小于负载长度,接收端必须响应一个PROTOCOL_ERROR连接错误。

 

例子

以gRPC的 HelloWorld 项目为例, 有关这个项目的搭建请参考: http://www.cnblogs.com/ghj1976/p/4549602.html

 

其中一个网络请求包的内容如下图截图:

这是来自 CommView 的 Loopback 网络请求监控的包, 如何使用 CommView 请参考: http://www.cnblogs.com/ghj1976/p/4554982.html 

 

这里黑色加量的部分是 RPC 特有的部分内容。

这部分包含2个帧,他们的分别数据如下:

00 00-0E 01 04 00 00 00 01 88 5F 8B 1D 75 D0 62 0D 26-3D 4C 4D 65 64

00 00 12 00 00 00 00 00 01 00 00-00 00 0D 0A 0B 48 65 6C 6C 6F 20 77 6F 72 6C 64     

 

Header 帧

00 00 0E 01 04 00 00 00 01 88 5F 8B 1D 75 D0 62 0D 26 3D 4C 4D 65 64

帧长度Length 为 00 00 0E ,即 14 + 9 长度共23 。

帧类型Type 为 01 标示是 Header 帧

帧的标志位Flags 为 04, 标示 END_HEADERS, 即这个Header帧不需要分片。

流标识符Stream Identifier 为 00 00 00 01 即,编号为1 。

Header 帧特有的串(Header Block Fragment): 88 5F 8B 1D 75 D0 62 0D 26 3D 4C 4D 65 64 
这里做了压缩,就不展开了, 相关知识请参考:  http://http2.github.com/http2-spec/compression.html

 

Data帧

00 00 12 00 00 00 00 00 01 00 00 00 00 0D 0A 0B 48 65 6C 6C 6F 20 77 6F 72 6C 64     

帧长度Length 为 00 00 12 即  18+9 = 27 
帧类型Type 为 00 标示是 Data 帧

帧的标志位Flags  00 
流标识符Stream Identifier 为 00 00 00 01 ,及 编号1, 对应上面的 Header 帧。

Data帧特有的串(Data 区域): 00 00 00 00 0D 0A 0B 48 65 6C 6C 6F 20 77 6F 72 6C 64

 

参考资料:

HTTP2协议中报文头可以采用Haffman编码,我们看到的报文头信息都是二进制信息。

HTTP2的报文格式请参考: http://www.blogjava.net/yongboy/archive/2015/03/20/423655.html

HTTP2报文头及数据帧格式解析实例分析

http://blog.csdn.net/jiayanhui2877/article/details/45074315 

Haffman 压缩算法请参考: http://coolshell.cn/articles/7459.html

HTTP2 帧基础知识以及Header、CONTINUATION、DATA帧相关资料:的更多相关文章

  1. 基础知识系列☞Abstract和Virtual→及相关知识

    转载地址→http://www.cnblogs.com/blsong/archive/2010/08/12/1798064.html 在C#的学习中,容易混淆virtual方法和abstract方法的 ...

  2. PHP面试 PHP基础知识 十一(开发环境及相关配置)

    开发环境及相关配置 版本控制软件 集中式和分布式 集中式:集中式版本控制工具,版本库集中存放在中央服务器,团队成员里的每个人工作时从中央服务器下载代码,个人修改后再提交到中央服务器 分布式:分布式版本 ...

  3. 基础知识系列☞GET和POST→及相关知识

    参考资料: [1].<IT企业必读的200个.Net面试题> [2].http://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.htm ...

  4. 基础知识:DFRduino UNO R3最全资料详解

    一.概述篇:1. 什么是DFRduino UNO R3?DFRduino UNO R3是一块基与开放原始代码的Simple i/o平台,並且具有使用类似java,C语言的开发环境.让您可以快速使用Ar ...

  5. 音视频处理基础知识扫盲:数字视频YUV像素表示法以及视频帧和编解码概念介绍

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt+moviepy音视频剪辑实战 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一. ...

  6. Data Base sqlServer基础知识

    sqlServer   基础知识 大纲 创建数据库 1 创建表 2 备份表 3 删除表 4 修改表 5 查询出重复的数据 6 增删改查 7 添加约束 8 分页存储过程 9 排序 10 类型转换 11 ...

  7. OpenGL ES 3.0 帧缓冲区对象基础知识

    最近在帧缓冲区对象这里卡了一下,不过前面已经了解了相关的OpenGL ES的知识,现在再去了解就感觉轻松多了.现在就进行总结. 基础知识 我们知道,在应用程序调用任何的OpenGL ES命令之前,需要 ...

  8. [terry笔记]data guard基础知识

    如下介绍了data guard的基础知识,整理自网络: Data Gurad 通过冗余数据来提供数据保护,Data Gurad 通过日志同步机制保证冗余数据和主数据之前的同步,这种同步可以是实时,延时 ...

  9. 网络工程知识(二)VLAN的基础和配置:802.1q帧;Access、Trunk、Hybrid接口工作模式过程与配置;VLANIF的小实验

    介绍-VLAN VLAN(Virtual Local Area Network)即虚拟局域网,工作在数据链路层. 交换机将通过:接口.MAC.基于子网.协议划分(IPv4和IPv6).基于策略的方式划 ...

随机推荐

  1. Java CAS ABA问题发生的场景分析

    提到了CAS操作存在问题,就是在CAS之前A变成B又变回A,CAS还是能够设置成功的,什么场景下会出现这个问题呢?查了一些资料,发现在下面的两种情况下会出现ABA问题. 1.A最开始的内存地址是X,然 ...

  2. BitMap算法详解

    所谓的BitMap就是用一个bit位来标记某个元素所对应的value,而key即是该元素,由于BitMap使用了bit位来存储数据,因此可以大大节省存储空间. 基本思想: 这此我用一个简单的例子来详细 ...

  3. [JavaScript] 根据字符串宽度截取字符串

    /** * 根据字符串宽度截取字符串 * @param desc 原始字符串 * @param width 该显示的宽度 * @param fontsize 字体大小 12px * @returns ...

  4. 基于mongoose 的增删改查操作

    无论是基于robomongo 的可视化工具,亦或是基于 mongoose 的函数工具,只要是对 mongodb 的操作,第一步都是开启数据库. 开启mongodb 数据库 进入mongod所在目录 执 ...

  5. PHP之旅3 php数组以及遍历数组 以及each() list() foreach()

    php的数组的定义 <?php //php中定义数组时可以通过索引直接进行赋值: $mArr[0]="哈哈"; $mArr[1]=70; $mArr[2]='haha'; e ...

  6. cmd下查看应用端口情况

    在win10开始窗口右侧的空白处点击CMD,在上方弹出窗口中选择命令提示符,双击进入 在弹出命令界面中,输入netstat -na命令后回车,如下图所示,可以看到所有目前打开的端口 如果要查看打开端口 ...

  7. Nginx+Tomcat搭建负载均衡

    一.       工具 nginx-1.8.0 apache-tomcat-6.0.33 二.    目标 实现高性能负载均衡的Tomcat集群: 三.    步骤 1.首先下载Nginx,要下载稳定 ...

  8. iOS--线程的创建

    1.获取当前线程 NSThread *current=[NSThread currentThread]; 2.获取主线程的另外一种方式 NSThread *main=[NSThread mainThr ...

  9. yii2之ActiveForm表单使用

    因目前项目并非前后端分离模式,且用到PHP的yii2框架(所有html代码,js较多内嵌在.php文件内多少采用同步提交[喷墨中...]),遂对于前端面上需要用到的yii2小组件一些整理(因是前端若涉 ...

  10. OO第一单元作业

    第一次作业 类图:   复杂度: 圈复杂度的问题一直困扰着这三次作业,主要体现在求导方法中先判断符号导致出现过多判断语句,应该将整理符号放在一个新的类中处理. 第一次作业由于对面向对象的思维有些不理解 ...