【问题标题】:C. Loop compression + send (gzip) ZLIBC.循环压缩+发送(gzip)ZLIB
【发布时间】:2018-07-13 09:52:47
【问题描述】:

我目前正在用 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'ed 缓冲区,这(当它们被连接时)是一个整体请求。

但是:目前,我的客户端(浏览器)只获取第一个缓冲区的信息。不过完全没有错误。

我如何完成这项工作,如何在循环中压缩一些缓冲区,以便我可以每次(在循环中)发送它们?

【问题讨论】:

    标签: c http compression gzip zlib


    【解决方案1】:

    首先,您需要在每次调用 deflate() 后对生成的 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。同样,看一下示例并阅读 cmets。

    【讨论】:

    • 好吧,这回答了我的担忧。我真的很感谢你的回答。非常感谢您的帮助。
    猜你喜欢
    • 2019-05-30
    • 1970-01-01
    • 1970-01-01
    • 2010-12-22
    • 1970-01-01
    • 2011-05-10
    • 1970-01-01
    • 2012-11-25
    • 1970-01-01
    相关资源
    最近更新 更多