C.循环压缩+发送(gzip)ZLIB

时间:2018-07-13 09:52:48

标签: c http compression 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一些缓冲区,以便每次(在循环中)发送它们?

1 个答案:

答案 0 :(得分:0)

首先,您需要在每次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个字节。

在您的情况下,您的CHUNKbuff大得多,该循环始终仅执行一次,因此您不会丢弃任何数据。但是,这只是由于Z_FINISH而发生,因此,在进行下一个修复时,将使用当前代码丢弃数据。

第二,每次输入不超过199个字节后,您将完成deflate()流。这将大大限制您可以获得的压缩量。此外,您将发送单独的gzip流,大多数浏览器仅会解释第一个gzip流。 (这实际上是这些浏览器中的错误,但我不认为它们会得到解决。)

您需要给压缩器至少10到100 KB的磁盘以进行适当的压缩。您需要使用Z_NO_FLUSH而不是Z_FINISH直到您要发送的最后一个buff为止。然后,您使用Z_FINISH。同样,请看一下示例并阅读评论。