HTTP 协议之 Chunked 解析

1. HTTP 协议之 Chunked 解析

在网上找了好一会, 始终没发现有解析 Chunked 编码的文章, 那就自己写一个吧, 呵呵。

网上使用 Chunked 编码的网站似乎并不是很多, 除了那些使用 GZip 压缩的网站, 例: google.com, 还有就是大部分打开 GZip 压缩的 PHP 论坛。

根据本人的理解, 使用 Chunked 编码的主要好处就在于一些程序的运算出过程中, 可以动态的输出内容。

例如, 要在后台处理一个小时的运算, 但又不希望用户等一个小时才能看到结果。这时就可采用 Chunked 编码将内容分块输出, 用户随时都可以接收到最新的处理结果。

ASP 关闭了缓存的输出模式, 就是 Chunked 编码的。(Response.Buffer = false)

而每一次的 Response.Write, 都是一个 Chunked, 所以不要使用的太频繁哦, 否则 Chunk 数量太多, 额外的数据太浪费空间了。

分块传输编码(Chunked transfer encoding)是超文本传输协议(HTTP)中的一种数据传输机制, 它允许 HTTP 由网页服务器发送给客户端应用的数据可以分成多个部分。

  • 使用限制: 分块传输编码只在 HTTP 协议 1.1 版本(HTTP/1.1)中提供。

通常情况下, HTTP 应答消息中发送的数据是整个发送的, Content-Length 消息头字段表示数据的长度。数据的长度很重要, 因为客户端需要知道哪里是应答消息的结束, 以及后续应答消息的开始

然而, 使用分块传输编码, 数据分解成一系列数据块, 并以一个或多个块发送, 这样服务器可以发送数据而不需要预先知道发送内容的总大小。

  • 分块传输编码的使用场景:

当客户端向服务器请求一个静态页面或者一张图片时, 服务器可以很清楚的知道内容大小, 然后通过 Content-Length 消息首部字段告诉客户端需要接收多少数据。但是如果是动态页面等时, 服务器是不可能预先知道内容大小, 这时就可以使用 Transfer-Encoding: chunk 模式来传输数据了。即如果要一边产生数据, 一边发给客户端, 服务器就需要使用"Transfer-Encoding: chunked"这样的方式来代替 Content-Length。

在进行 chunked 编码传输时, 在回复消息的头部有 Transfer-Encoding: chunked

  • 分块传输编码的编码格式:

编码使用若干个 chunk 组成, 由一个标明长度为 0 的 chunk 结束。每个 chunk 有两部分组成, 第一部分是该 chunk 的长度, 第二部分就是指定长度的内容, 每个部分用 CRLF 隔开。在最后一个长度为 0 的 chunk 中的内容是称为 footer 的内容, 是一些没有写的头部内容。

chunk 编码格式如下:

[chunk size][\r\n][chunk data][\r\n][chunk size][\r\n][chunk data][\r\n][chunk size = 0][\r\n][\r\n]

chunk size 是以十六进制的 ASCII 码表示, 比如: 头部是 3134 这两个字节, 表示的是 1 和 4 这两个 ascii 字符, 被 http 协议解释为十六进制数 14, 也就是十进制的 20, 后面紧跟 [\r\n](0d 0a), 再接着是连续的 20 个字节的 chunk 正文。chunk 数据以 0 长度的 chunk 块结束, 也就是(30 0d 0a 0d 0a)。

分块编码传输的译码过程:

最最开始的地方: 你需要先确认你收到的数据时使用的 chunked 编码, 也就是找到 Transfer-Encoding: chunked, 如果你找到了, 好的, 那接下来就可以按照下面的步骤开始进行解析了。

  1. 你需要找到数据开始地方, 也就是第一个 chunk size 开始的地方, 这个地方的标识符为、r\n\r\n
  2. 你要成功获取到这一块的数据长度, 这个地方需要注意了, 十六进制的 ASCII 码表示。是的, 字符串转成数字, 你想起来函数 atoi() 了吗? 恭喜你, 你函数选择错了, atoi() 只能识别数字 0-9, 遇到 A-F 就截断了, 不过不用担心, 还有一个函数叫做 strtol(), 它可以随意的转换 2-36 进制。
  3. 获取到数据块长度了, 就可以 copy 数据了是吧, 是不是很简单, 但是如果你使用了 str ***相关的函数, 那么恭喜你, 你又错了, 他们遇到、0 就会停止, 而你需要 copy 的数据可能会遇到很多歌、0, 还好有 memcpy() 这一类的函数可以使用。如果数据时写到指针里面, 多次 copy 数据时记得指针的偏移
  4. 接下就跳过、r\n 去获取下一个数据块长度, 然后 copy 数据吧, 直到你遇到一个数据块的长度为 0, 到这里数据就完全获取成功了。

看到了这里就会发现里面数据获取的方式是拼接, 就是舍弃数据块长度, \r\n, 只要数据块。是不是很简单?

下面就说说我之前的解析想法以及错误的原因吧。

我之前没有想到用到长度这个数据, 而是看到了 “\r\n 数据块、r\n”, 于是我就想到通过查找"\r\n"来提取数据, 如果你认真的看了上面过程中我的解析, 你就知道原因了。是的, 数据块中有、0, 所以我没有找到我想要的 “\r\n”, 就解析失败了。

所以一定要用好字符串函数。一定。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云满笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值