zlib对http中chunk数据解压

来源:互联网 发布:java 判断日期格式 编辑:程序博客网 时间:2024/05/16 06:03
1 数据包内存的提取:
关键的地方是找到gzip内存的开始位置以及如何确定gzip内容的大小
开始位置:“Content-Encoding: gzip\r\n\r\n”
gzip大小:“Content-Length:”后面的就是了
2 数据包的重组,一般网页的内容很少是一个数据包可以装得下的,所以都得进行gzip之后再用多个数据包进行传输
关键的地方是:
get请求数据包的ack和seq与http返回数据包的ack,seq有密切的联系:
举例说明:
get请求:ack=0,seq=0
http1:seq=0,ack=584
http2: seq=1420,ack=584
...
简单的分析说明可以看出,我们的算法设计:
首先得到get请求的ack,返回的数据包的seq等于这个值,同时记下这个数据包的ack,后面进行分包发送的http的数据包的ack都是这个值,这个是关键点之一,同时综合
Content-Length就可以得到gzip的全部内容。
至此,原始数据提取完毕,该是如何解压的问题了
3解压gzip
我做了上面的1,2步以后将内容保存到文件里面,用gzip命令可以打开,验证了数据的完整性。
后我采用了zlib提供的uncompress函数,和大多数的网友一样,都是犯了一个致命的错误,没有仔细的阅读zlib的文档!导致一次次无谓的识别!
事实上zlib格式和gzib格式是有差别的,而uncompress是用来解压zlib格式文件的,这就是为什么会出现用compress函数压缩的数据,在内存中可以直接用uncompress函数进行解压的,而就不能解压gzip数据的问题! 

后来测试了zlib包里面的example例子,算是对zlib有了一点点的了解,应该用inflate类函数进行解压!
当然这样遇到了问题,格式不对!

后来在网上看到的帖子:gzip格式用inflate函数还不行,必需要用inflateInit2(&strm, 47); !!!!!!!!!!!!!!!!!!
问题解决!
这里借用那位网友的源代码,同时对他表示感谢!

int inflate_read(char *source,int len,char **dest,int gzip)

int ret; 
unsigned have; 
z_stream strm; 
unsigned char out[CHUNK]; 
int totalsize = 0; 

/* allocate inflate state */ 
strm.zalloc = Z_NULL; 
strm.zfree = Z_NULL; 
strm.opaque = Z_NULL; 
strm.avail_in = 0; 
strm.next_in = Z_NULL; 

if(gzip) 
ret = inflateInit2(&strm, 47); 
else 
ret = inflateInit(&strm); 

if (ret != Z_OK) 
return ret; 

strm.avail_in = len; 
strm.next_in = source; 

/* run inflate() on input until output buffer not full */ 
do { 
strm.avail_out = CHUNK; 
strm.next_out = out; 
ret = inflate(&strm, Z_NO_FLUSH); 
assert(ret != Z_STREAM_ERROR); /* state not clobbered */ 
switch (ret) { 
case Z_NEED_DICT: 
ret = Z_DATA_ERROR; /* and fall through */ 
case Z_DATA_ERROR: 
case Z_MEM_ERROR: 
inflateEnd(&strm); 
return ret; 

have = CHUNK - strm.avail_out; 
totalsize += have; 
*dest = realloc(*dest,totalsize); 
memcpy(*dest + totalsize - have,out,have); 
} while (strm.avail_out == 0); 

/* clean up and return */ 
(void)inflateEnd(&strm); 
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; 

}


感谢Squallxye



下面是我自己做的实验,确实通过了


#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include "../include/zlib.h"
#pragma comment(lib,"zdll.lib")

int main(int argc, char* argv[])
{
    FILE *comp = fopen("C:\\wode.gz", "rb");
    FILE *uncomp = fopen("C:\\wodelog.txt", "wb");
    
    fseek(comp, 0, SEEK_END);
    unsigned long complen = ftell(comp);
    
    void *RawDataBuff = malloc(complen);
    void *UnCompDataBuff = NULL;
    
    fseek(comp, 0, SEEK_SET);
    fread(RawDataBuff, complen , 1, comp);

    uLongf UnComplen = complen*4;
    UnCompDataBuff = malloc(UnComplen);
    
    int err;
    z_stream d_stream;
    d_stream.zalloc = (alloc_func)0;
    d_stream.zfree = (free_func)0;
    d_stream.opaque = (voidpf)0;
    
    d_stream.next_in = (Byte*)RawDataBuff;
    d_stream.avail_in = 0;
    d_stream.next_out = (Byte*)UnCompDataBuff;
    
    err = inflateInit2(&d_stream,47);
    if(err!=Z_OK)
    {
        printf("inflateInit2 error:%d",err);
        return NULL;
    }
    while (d_stream.total_out < UnComplen && d_stream.total_in < UnComplen) {
        d_stream.avail_in = d_stream.avail_out = 1;
        err = inflate(&d_stream,Z_NO_FLUSH);
        if(err == Z_STREAM_END) break;
        if(err!=Z_OK)
        {
            printf("inflate error:%d",err);
            return NULL;
        }
    }
    err = inflateEnd(&d_stream);
    if( err != Z_OK )
    {
        printf( "inflateEnd error:%d" , err );
        return NULL;
    }
    char* b = new char[d_stream.total_out+1];
    memset(b,0,d_stream.total_out+1);
    memcpy(b,(char*)UnCompDataBuff,d_stream.total_out);
    
    fwrite( b , d_stream.total_out+1, 1, uncomp);
    return 0;
}


希望做个笔记,以后别忘了



原创粉丝点击