C语言 HTTP中的chunked解码实现

C语言不像C#一样有很多很多高度的模块化的东西可以使用,在通讯过程中特别是与http相关的通讯过程中可能要对网站返回的数据做一定处理,而且有不少网站的回应是强制性的,例如向网站请求deflate有个能会返回的是gzip的数据。在这过程中与web特性有关的,在服务器构造消息之前可能并不知道或者不方便知道消息的长度,于是就会将消息分为一段段进行传送。

例如如下回应:

不难发现,chunked正式实现这一思想的方式。

每个HTTP头部含有Transfer-Encoding: chunked则表明此包Data是分块传输的。关于他的介绍痿基百科上说的很多,有兴趣可以看看http://en.wikipedia.org/wiki/Chunked_transfer_encoding

实质上我们做的工作就是要对HTTP返回的头部含有Transfer-Encoding: chunked的数据做解码工作。

数据结构如下:长度[HEX]\r\n内容\r\n长度[HEX]\r\n内容\r\n\0\r\n\r\n

解码过程当然很简单,没涉及任何数学知识,或者更本谈不上解码,知识做合并工作罢了。。。

C语言能用的找了10分钟百度不到,除了一段满是奇怪参缺少函数的数狗啃的,索性干脆自己写一个算了。。。

以下是C(C++)实现代码,在1块长度112下测试通过,应该没什么BUG。有的话烦请只出,代码应该算得上严谨了。

 1 /*
2 * 十六进制表示的字符串转换为相应的十进制值 传入"7f"返回127
3 */
4 int htoi(unsigned char *s)
5 {
6 int i;
7 int n = 0;
8 if (s[0] == '0' && (s[1]=='x' || s[1]=='X')) //判断是否有前导0x或者0X
9 {
10 i = 2;
11 }
12 else
13 {
14 i = 0;
15 }
16 for (; (s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'z') || (s[i] >='A' && s[i] <= 'Z');++i)
17 {
18 if (tolower(s[i]) > '9')
19 {
20 n = 16 * n + (10 + tolower(s[i]) - 'a');
21 }
22 else
23 {
24 n = 16 * n + (tolower(s[i]) - '0');
25 }
26 }
27 return n;
28 }
29
30 /*
31 * 查找关键数据串在长数据中出现的位置
32 * 参数:1长数据指针,2搜索最大长度,3关键字指针,4关键字长度,5搜索起始位置(返回出现位置,若未找到则不变)
33 * 返回:返回1 成功 返回 0 未找到
34 */
35 int _find_key(unsigned char *data,int data_length,unsigned char *key,int key_length,int *position)
36 {
37 int i = *position;
38 if(key == NULL || i<0)
39 {
40 return 0;
41 }
42 for(; i <= data_length-key_length; i++)
43 {
44 if( memcmp(data+i, key, key_length) == 0 )
45 {
46 *position = i;
47 return 1;
48 }
49 }
50 return 0;
51 }
52
53 /*
54 * 对HTTP的chunked消息进行合块
55 * 参数:1待处理数据,2数据长度(分配的长度即可,不一定要求出实际有效长度),3返回合块后的数据,4合块长度
56 * 算法具有前驱性,返回和传入data可以是同一块内存区域(不建议)
57 */
58 int de_chunked(unsigned char *data,int data_length,unsigned char *dest,int *dest_length)
59 {
60 char chunked_hex[CHUNKED_MAX_LEN + 1]; // 十六进制的块长度
61 int chunked_len; // 块长度
62 int ret;
63 int begin = 0;
64 int end = 0;
65 int i = 0;
66 int index = 0;
67
68 ret = _find_key(data,data_length,"0\r\n\r\n",5,&end);
69 if (ret == 0) //信息不完整
70 return 0;
71
72 ret = _find_key(data,data_length,"\r\n\r\n",4,&begin);
73 begin = begin + 4; //移动到数据起点
74
75 while(memcmp(data+begin,"0\r\n\r\n",5) != 0)
76 {
77 //获得当前块长度
78 ret = _find_key(data+begin,CHUNKED_MAX_LEN,"\r\n",2,&i);
79 if (ret == 0) //信息不完整
80 return 0;
81 memcpy(chunked_hex,data+begin,i);
82 chunked_hex[i] = '\0';
83 chunked_len = htoi(chunked_hex);
84 //移动到当前块数据段
85 begin = begin + i + 2;
86 //获得当前块数据
87 if (memcmp(data+begin+chunked_len,"\r\n",2) != 0)
88 return 0; //信息有误
89 memcpy(dest+index,data+begin,chunked_len);
90 index = index + chunked_len;
91 //移动到下一块块长度
92 begin = begin + chunked_len + 2;
93 i = begin;
94 if(begin > end) //结构错误
95 return -1;
96 }
97 *dest_length = index;
98 return 1;
99 }



 

转载于:https://www.cnblogs.com/dsblab/archive/2012/01/23/2328905.html

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
HTTP chunked编码是HTTP协议传输数据的一种方式,其本质上是将数据分成若干个小块进行传输,每个小块包含一定量的数据,以及用于表示数据块长度的十六进制数字。 Java提供了一些类和方法来解码HTTP chunked消息。在Java,可以使用HttpURLConnection类的getResponseCode()方法来获取HTTP响应的状态码。如果响应状态码为200,则可以使用getInputStream()方法来获取响应内容。此时,需要创建一个新的GZIPInputStream对象,并将getInputStream()的返回值作为参数传入。如果HTTP响应使用了chunked编码,则需要使用ChunkedInputStream类进行解码。此类继承了FilterInputStream类,并在read()方法自动处理chunked格式。 在Java,可以使用Apache HTTP Components库进行HTTP chunked编码的解码。具体来说,可以使用ChunkedInputStream类或者ChunkedEntity类来对chunked编码的HTTP响应消息进行解码。可以通过调用ChunkedInputStream类的read()方法来读取数据并将其解码。这个类可以处理chunked编码格式的消息,并自动进行解码。另外,ChunkedEntity类也可以实现HTTP chunked编码的解码,它可以将HTTP实体转换为一个正常的输入流。如果要使用该类进行解码,则需要创建一个HttpEntity对象,并将其作为参数传入ChunkedEntity类的构造函数。 总之,使用Java进行HTTP chunked编码的解码相对比较简单,开发人员只需要了解Java提供的类和方法,并说明消息所采用的编码格式,就可以比较轻松地实现解码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值