C.循环压缩+发送(gzip)ZLIB
C. Loop compression + send (gzip) ZLIB
我目前正在用 C 构建一个 HTTP 服务器。
请注意这段代码:
#define CHUNK 0x4000
z_stream strm;
unsigned char out[CHUNK];
int ret;
char buff[200];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
int windowsBits = 15;
int GZIP_ENCODING = 16;
ret = deflateInit2(&strm, Z_BEST_SPEED, Z_DEFLATED, windowsBits | GZIP_ENCODING, 1,
Z_DEFAULT_STRATEGY);
fill(buff); //fill buff with infos
do {
strm.next_in = (z_const unsigned char *)buff;
strm.avail_in = strlen(buff);
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = deflate(&strm, Z_FINISH);
} while (strm.avail_out == 0);
send_to_client(out); //sending a part of the gzip encoded string
fill(buff);
}while(strlen(buff)!=0);
我的想法是:我正在尝试一个一个地发送 gzip 压缩缓冲区,(当它们连接时)是一个整体请求。
但是:目前,我的客户端(浏览器)只获取第一个缓冲区的信息。不过完全没有错误。
我如何完成这项工作,如何在循环中 gzip 一些缓冲区以便我可以每次(在循环中)发送它们?
首先,您需要在每次 deflate()
调用后对生成的压缩数据执行一些操作。您的代码丢弃了在内部循环中生成的压缩数据。从 this example 开始,在 deflate()
之后,您需要这样的东西:
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)deflateEnd(&strm);
return Z_ERRNO;
}
这就是您的 send_to_client
需要发送 have
字节的地方。
在你的例子中,你的 CHUNK
比你的 buff
大得多,那个循环总是只执行一次,所以你没有丢弃任何数据。然而,这只是因为 Z_FINISH
,所以当您进行下一次修复时,您将丢弃当前代码中的数据。
其次,您每次在不超过 199 个字节的输入后完成 deflate()
流。这将极大地限制您可以获得多少压缩。此外,您发送的是单独的 gzip 流,大多数浏览器只会解释第一个。 (这实际上是那些浏览器中的错误,但我不认为它们会被修复。)
您需要为压缩器提供至少 10 到 100 千字节的空间才能获得良好的压缩效果。您需要使用 Z_NO_FLUSH
而不是 Z_FINISH
,直到您到达最后一个要发送的 buff
。然后你使用 Z_FINISH
。再次查看示例并阅读评论。
我目前正在用 C 构建一个 HTTP 服务器。
请注意这段代码:
#define CHUNK 0x4000
z_stream strm;
unsigned char out[CHUNK];
int ret;
char buff[200];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
int windowsBits = 15;
int GZIP_ENCODING = 16;
ret = deflateInit2(&strm, Z_BEST_SPEED, Z_DEFLATED, windowsBits | GZIP_ENCODING, 1,
Z_DEFAULT_STRATEGY);
fill(buff); //fill buff with infos
do {
strm.next_in = (z_const unsigned char *)buff;
strm.avail_in = strlen(buff);
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = deflate(&strm, Z_FINISH);
} while (strm.avail_out == 0);
send_to_client(out); //sending a part of the gzip encoded string
fill(buff);
}while(strlen(buff)!=0);
我的想法是:我正在尝试一个一个地发送 gzip 压缩缓冲区,(当它们连接时)是一个整体请求。
但是:目前,我的客户端(浏览器)只获取第一个缓冲区的信息。不过完全没有错误。
我如何完成这项工作,如何在循环中 gzip 一些缓冲区以便我可以每次(在循环中)发送它们?
首先,您需要在每次 deflate()
调用后对生成的压缩数据执行一些操作。您的代码丢弃了在内部循环中生成的压缩数据。从 this example 开始,在 deflate()
之后,您需要这样的东西:
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)deflateEnd(&strm);
return Z_ERRNO;
}
这就是您的 send_to_client
需要发送 have
字节的地方。
在你的例子中,你的 CHUNK
比你的 buff
大得多,那个循环总是只执行一次,所以你没有丢弃任何数据。然而,这只是因为 Z_FINISH
,所以当您进行下一次修复时,您将丢弃当前代码中的数据。
其次,您每次在不超过 199 个字节的输入后完成 deflate()
流。这将极大地限制您可以获得多少压缩。此外,您发送的是单独的 gzip 流,大多数浏览器只会解释第一个。 (这实际上是那些浏览器中的错误,但我不认为它们会被修复。)
您需要为压缩器提供至少 10 到 100 千字节的空间才能获得良好的压缩效果。您需要使用 Z_NO_FLUSH
而不是 Z_FINISH
,直到您到达最后一个要发送的 buff
。然后你使用 Z_FINISH
。再次查看示例并阅读评论。