在进行微博数据解析的过程中,遇到了gzip格式的压缩数据,要从这些数据中得到微博信息就首先需要对gzip数据进行解压。
这里采用的解压工具是zlib(http://www.zlib.net/),关于zlib的技术细节参考http://www.zlib.net/zlib_tech.html。
重组后的微博TCP会话中的压缩数据:
从上图可以看出,gzip数据的开始是从两个换行“\r\n”开始的,即从“65c”这行数据后边开始的,是以“0”这一行结束的。”65c“表示的是其下面那段压缩数据的长度;上图中gzip数据仅分了65c这么长的一段,而某次压缩的数据可能分多个段,那么每段数据均以类似"65c"这么一个表示长度的值开始,后跟本段压缩数据。
下面这个函数是将一段一段的压缩gzip数据进行合并:
//第一个参数是待处理的http数据,第二个参数是数据的长度
//该函数处理重组后的http数据中的gzip压缩数据:
//gzip数据是以一个或多个chunked的形式存在的,该函数将提取,合并并解压出所有chunk的数据(解压
//出的gzip数据是是json格式的,函数返回的解压内容,在后续处理中会提取出json的“html”字段,进一步得到微博id)
void ProcessGzipData(char *source, int len, char *decompression) {
char result_gzip[65530];
char pattern[] = "\r\n\r\n";
int begin_pos = KmpSearch(source, len, pattern) + strlen(pattern);
if (begin_pos == -1)
return;
int offset = 0;
int gzip_len = 0;
while (memcmp(source + begin_pos + offset, "0\r\n", 3) != 0) {
char pattern2[] = "\r\n";
int len1 = KmpSearch(source + begin_pos + offset, len - begin_pos - offset, pattern2);
if (len1 == -1) //压缩数据出错,返回
break;
char temp1[10] = {'\0'};
memcpy(temp1, source + begin_pos + offset, len1);
offset += (len1 + strlen("\r\n"));
int len2 = KmpSearch(source + begin_pos + offset, len - begin_pos - offset, pattern2);
memmove(result_gzip + gzip_len, source + begin_pos + offset, len2);
gzip_len += len2;
offset += (len2 + strlen("\r\n"));
}
/*
fstream myfile("/home/yang/test/zlib.file", fstream::in | fstream::out | fstream::app);
if (!myfile)
cout << "open file error" << endl;
int i;
cout << "gzip len: " << gzip_len << endl;
for (i = 0; i < gzip_len; ++i)
myfile << result_gzip[i];
myfile.close();
*/
DecompressGzip(result_gzip, gzip_len + 1000, decompression); //调用下面的函数对合并的gzip数据解压
}
解压gzip数据的代码如下:
//该函数解压gzip数据
//参数:source是指向待解压数据的指针;len是待解压数据的长度;destination用于存放解压后的数据
int DecompressGzip(char *source, int len, char *destination) {
int result, have;
int offset = 0;
z_stream d_stream;
unsigned char compression[SEGMENT_SIZE] = {'\0'}, decompression[SEGMENT_SIZE] = {'\0'};
memcpy(compression, (Byte*)source, len);
unsigned int compression_len = len, decompression_len = SEGMENT_SIZE * 4;
strcpy((char*)decompression, "garbage");
d_stream.zalloc = Z_NULL;
d_stream.zfree = Z_NULL;
d_stream.opaque = Z_NULL;
d_stream.next_in = Z_NULL;
d_stream.avail_in = 0;
result = inflateInit2(&d_stream, 47);
if (result != Z_OK) {
printf("inflateInit2 error: %d\n", result);
return result;
}
d_stream.next_in = compression;
d_stream.avail_in = compression_len;
do {
d_stream.next_out = decompression;
d_stream.avail_out = SEGMENT_SIZE;
result = inflate(&d_stream, Z_NO_FLUSH);
assert(result != Z_STREAM_ERROR);
switch (result) {
case Z_NEED_DICT:
result = Z_DATA_ERROR;
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&d_stream);
return result;
}
have = SEGMENT_SIZE - d_stream.avail_out;
memcpy(destination + offset, decompression, have);
offset += have;
} while (d_stream.avail_out == 0);
inflateEnd(&d_stream);
memcpy(destination + offset, "\0", 1);
return result;
}
参考:
zlib and gzip
获取http的gzip内容并解压相关问题
gzip 使用zlib解压http中gzip内容
zlib库解压http报文中的gzip数据
RFC:GZIP file format specification version 4.3版权声明:本文为u013074465原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。