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] 内容 长度[HEX] 内容
解码过程当然很简单,没涉及任何数学知识,或者更本谈不上解码,只是做合并工作罢了。。。
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 ",5,&end); 69 if (ret == 0) //信息不完整 70 return 0; 71 72 ret = _find_key(data,data_length," ",4,&begin); 73 begin = begin + 4; //移动到数据起点 74 75 while(memcmp(data+begin,"0 ",5) != 0) 76 { 77 //获得当前块长度 78 ret = _find_key(data+begin,CHUNKED_MAX_LEN," ",2,&i); 79 if (ret == 0) //信息不完整 80 return 0; 81 memcpy(chunked_hex,data+begin,i); 82 chunked_hex[i] = '