我在解压缩gzip http响应方面遇到的问题很少,我将数据部分与头文件分开,但是它的gzip头和消息包含\ 0字符,其中char *作为空终止符,所以第一个问题是如何提取gzip压缩块?
我不能使用像strcat,strlen这样的字符串函数,因为它是压缩的gzip压缩数据,在块内的不同位置包含\ 0字符。
我使用了libcurl,但它比C套接字慢。
以下是样本回复的一部分:
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: text/html; charset=utf-8
P3P: CP="NON UNI COM NAV STA LOC CURa DEVa PSAa PSDa OUR IND"
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 12605
Date: Mon, 05 Mar 2012 11:46:30 GMT
Connection: keep-alive
Set-Cookie: _FP=EM=1; expires=Wed, 05-Mar-2014 11:46:29 GMT; domain=.bing.com; path=/
����ՠ����AU��o�
示例代码:
#define MAXDATASIZE 1024
char *recvData; // Holds entire gzip data
char recvBuff[MAXDATASIZE]; // Holds gzip chunk
int offset=0;
while(1){
recvBytes = recv(sockfd, &recvBuff, MAXDATASIZE-1, 0);
totalRecvBytes += recvBytes;
// get content length, this runs first time only as required
if(!clfnd){
regi = regexec(&clregex, &recvBuff, 3, clmatch, 0);
if(!regi){
strncpy(clarr, recvBuff + clmatch[2].rm_so, clmatch[2].rm_eo-clmatch[2].rm_so);
clarr[clmatch[2].rm_eo-clmatch[2].rm_so] = '\0';
cl = atoi(clarr);
clfnd=1;
regfree(&clregex);
recvData = malloc(cl * sizeof(char));
memset(recvData, 0, sizeof recvData);
}
}
// get data part from 1st iteration, furthur iterations contain only data
if(!datasplit){
int strtidx;
char *datastrt = strstr(&recvBuff, "\r\n\r\n");
if(datastrt != NULL){
strtidx = datastrt - recvBuff + 4;
memcpy(recvData, recvBuff + strtidx, recvBytes-strtidx);
datasplit=1;
offset = recvBytes-strtidx;
}
}
else{
memcpy(recvData + offset, recvBuff, recvBytes);
offset += recvBytes;
}
if (offset >= cl)
break;
}
char *outData = malloc(offset*4 * sizeof(char));
memset(outData, 0, sizeof outData);
int ret = inf(recvData, offset, outData, offset*4);
充气功能:
int inf(const char *src, int srcLen, const char *dst, int dstLen){
z_stream strm;
strm.zalloc=NULL;
strm.zfree=NULL;
strm.opaque=NULL;
strm.avail_in = srcLen;
strm.avail_out = dstLen;
strm.next_in = (Bytef *)src;
strm.next_out = (Bytef *)dst;
int err=-1, ret=-1;
err = inflateInit2(&strm, MAX_WBITS+16);
if (err == Z_OK){
err = inflate(&strm, Z_FINISH);
if (err == Z_STREAM_END){
ret = strm.total_out;
}
else{
inflateEnd(&strm);
return err;
}
}
else{
inflateEnd(&strm);
return err;
}
inflateEnd(&strm);
printf("%s\n", dst);
return err;
}
答案 0 :(得分:4)
不,类型char *
没有说明它指向的内容,也没有将任何值解释为终结符。另一方面,str *函数假设有关字符串的表示方式,不能用于二进制数据,甚至不能用于具有不同表示的文本数据。
减压可能相当复杂,但您可以查看zlib,这应该可以帮助您。
答案 1 :(得分:2)
Content-Length:12605表示gzip压缩文件的大小为12605字节。因此,只需将消息头之后的12605个字节复制到本地缓冲区,并将该缓冲区提供给解压缩功能。此外,我不确定您的套接字读取功能是否在一个流程中读取整个12605。如果没有,则需要将下一次读取的其余数据附加到此本地缓冲区,并在读取12605个字节时再调用解压缩函数。 使用char *作为缓冲区没有问题。您面临的问题是因为您尝试将gzip数据打印为字符串。
答案 2 :(得分:0)
HTTP有效负载的开头在“\ r \ n \ r \ n”之后(在HTTP标头之后)开始。
使用HTTP字段“Content-Length”获取HTTP有效负载大小。
使用此信息,您必须创建解压缩数据的功能。使用Zlib,你可以做到这一点。
PS。如果它使用原始格式或带有标题和预告片的zlib,请注意。 Usualy HTTP使用标题和预告片,IMAP4使用原始格式。