问题

后台服务传包太大时,我们框架可以使用 zlib 库对响应进行压缩;在这次服务调试过程中,使用 zlib compress2Z_BEST_COMPRESSION 模式进行压缩时,报 Z_BUF_ERROR(-5) 错误

分析

bool Codec::ZlibCompress(const std::string& src , std::string& compr_str)
{
int max_size = src.size();
if(max_size == 0)
{
return false;
}
DataBuffer<char> compr(max_size);
memset(compr, 0, max_size);
uLongf compr_len = max_size;
int res = compress2((Bytef*)compr.Get(),&compr_len,(const Bytef*)(src.c_str()),src.size(),9);
if(res != Z_OK)
{
return false;
} compr_str = Base64Encode((const void*)compr,compr_len);
return true;
}

这里 compress2 的输出缓冲区大小设置成为待压缩原串的长度了,在压缩数据太小或随机性很大等情况下,压缩得到的数据可能会比原来的大,导致 Z_BUF_ERROR;

下面的数据是对随机字符的压缩情况,src_size 为原串大小,compr size 为压缩后长度,说明在字符很随机的情况下,压缩完再使用 Base64Encode(Base64 编码数据会增大 1/3),长度一般都会变大。

解决

int compressBound(uLong sourceLen);

zlib 提供了一个 compressBound 方法,用于估算调用一次 compress2()/compress(),用于压缩 sourceLen 长度数据所需输出缓冲区的最大大小。

但是框架压缩后,对压缩串进行 Base64 编码(Base64 编码数据会增大 1/3),最终的输出缓冲区大小应该至少设置为 compressBound(sourceLen) * 4 / 3,因此改后的代码为:

bool Codec::ZlibCompress(const std::string& src , std::string& compr_str)
{
int src_size = src.size(); // 原串则不进行压缩,且压缩输出串置空
if(0 == src_size)
{
compr_str = "";
return true;
} /*
经过测试,在 best_compress(9) 的模式下,由随机字符构成的原串,压缩输出串有可能比原串长度大
由随机字符构成的原串,长度在 0-40k 情况下,output_buffer_size / compressBound() * 100 最大为 133.33(best_compress 和 best_speed 下此值一样)
为保证输出缓冲区足够大,缓冲区大小设置为 compressBound() * 2
*/
int max_size = compressBound(src_size) * 2; // 如果得到的输出缓冲区大小不大于 0,则返回压缩失败
if(max_size <= 0)
{
return false;
} DataBuffer<char> compr(max_size);
uLongf compr_len = max_size;
int res = compress2((Bytef*)compr.Get(),&compr_len,(const Bytef*)(src.c_str()),src_size,9);
if(res != Z_OK)
{
return false;
} compr_str = Base64Encode((const void*)compr,compr_len);
return true;
} bool Codec::ZlibDecompress(const std::string& base64_src , std::string& decmpr_str)
{
int size = base64_src.size(); if(0 == size)
{
decmpr_str = "";
return true;
} DataBuffer<char> src(base64_src.size());
int base64_res = Base64Decode((const char*)(base64_src.c_str()),base64_src.size(),(void*)src,&size);
if(base64_res != 0)
{
return false;
}
int max_size = size*30;
DataBuffer<char> decompr(max_size);
uLongf decompr_len = max_size;
uLong src_size = size;
int res = uncompress2((Bytef*)decompr.Get(),&decompr_len,(const Bytef*)src.Get(),&src_size);
if(res != Z_OK)
{
return false;
}
decmpr_str = std::string(decompr , decompr_len);
return true;
}

参考

compressBound

http://refspecs.linuxbase.org/LSB_3.0.0/LSB-PDA/LSB-PDA/zlib-compressbound-1.html

In what situation would compressed data be larger than input?

https://stackoverflow.com/questions/16992754/in-what-situation-would-compressed-data-be-larger-than-input

zlib详细基础教程

https://www.0xaa55.com/thread-442-1-1.html

zlib 压缩输出缓冲区 overflow 问题的更多相关文章

  1. PHP基础之输出缓冲区基本概念、原理分析

    一.概念 在PHP运行的过程中,可以将会产生输出的函数或操作结果暂时保存在PHP的缓冲区,只有当缓冲区满了.或者PHP运行完毕.或者在必要时候进行输出,才会将数据输出到浏览器,此缓冲数据的区域称为PH ...

  2. 深入理解php的输出缓冲区(output buffer)

    这篇文章是翻译自Julien Pauli的博客文章PHP output buffer in deep,Julien是PHP源码的资深开发和维护人员.这篇文章从多个方面讲解了PHP中的输出缓冲区以及怎么 ...

  3. PHP中zlib扩展实现GZIP压缩输出各种方法总结

    一般情况下我们出现大量数据传输理希望减少服务器的带宽压力,会采取一种方式来压缩文件传输,php中用zlib也可以实现gzip压缩输出,下面我们来看GZIP压缩输出各种方法总结. GZIP(GNU-ZI ...

  4. 饼干是这样压缩的——PHP使用zlib扩展实现页面GZIP压缩输出

    饼干是这样压缩的——PHP使用zlib扩展实现页面GZIP压缩输出 GZIP(GNU-ZIP)是一种压缩技术.经过GZIP压缩后页面大小可以变为原来的30%甚至更小.这样用户浏览的时候就会感觉很爽很愉 ...

  5. PHP的输出缓冲区(转)

    什么是缓冲区?简单而言,缓冲区的作用就是,把输入或者输出的内容先放进内存,而不显示或者读取.至于为什么要有缓冲区,这是一个很广泛的问题,如果有兴趣,可以在网山找下资料.其实缓冲区最本质的作用就是,协调 ...

  6. PHP的输出缓冲区

    什么是缓冲区?简单而言,缓冲区的作用就是,把输入或者输出的内容先放进内存,而不显示或者读取.至于为什么要有缓冲区,这是一个很广泛的问题,如果有兴趣,可以在网山找下资料.其实缓冲区最本质的作用就是,协调 ...

  7. zlib打印bit length overflow

    bit length overflow code bits -> code bits -> zlib库输出此log,此log不代表压缩出现错误,没有什么危害,而且zlib非常稳定,完全可以 ...

  8. Nginx_地址重写(rewrite)_日志管理(log_format)_压缩输出_Nginx设定限速_Nginx设置反向代理及反向代理缓存

    Nginx地址重写 Nginx rewrite rewrite语法规则1).变量名可以使用 "=" 或 "!=" 运算符~ 区分大小写~* 不区分大小写^~ 禁 ...

  9. Delphi Base64编码/解码及ZLib压缩/解压

    最近在写的程序与SOAP相关,所以用到了一些Base64编码/解码及数据压缩/解压方面的知识. 在这里来作一些总结:   一.Base64编码/解码   一般用到的是Delphi自带的单元EncdDe ...

随机推荐

  1. Python的time(时间戳与时间字符串互相转化)

    strptime("string format")字符串如"20130512000000"格式的 输入处理函数 localtime(float a)时间戳的输入 ...

  2. 【算法导论】八皇后问题的算法实现(C、MATLAB、Python版)

    八皇后问题是一道经典的回溯问题.问题描述如下:皇后可以在横.竖.斜线上不限步数地吃掉其他棋子.如何将8个皇后放在棋盘上(有8*8个方格),使它们谁也不能被吃掉?         看到这个问题,最容易想 ...

  3. 网站开发进阶(二十一)Angular项目信息错位显示问题解决

    Angular项目信息错位显示问题解决 绪 最近在项目开发过程中遇到这样一个棘手的问题:查询出所有订单信息后,点击选择某一个订单,查询出的结果是上一次查询所得的结果.而且会出现点击两次才可以显示订单详 ...

  4. 报表软件公司高价悬赏BUG,100块1个我真是醉了

    一直在用帆软的报表软件FineReport来做项目,也一直关注着这个公司的发展. 看到<提BUG,拿奖金>的这个活动,有些疑问和思考. 一般FineReport新版本在正式发布前,都会经过 ...

  5. TCP的核心系列 — ACK的处理(二)

    本文主要内容:tcp_ack()中的一些细节,如发送窗口的更新.持续定时器等. 内核版本:3.2.12 Author:zhangskd @ csdn 发送窗口的更新 什么时候需要更新发送窗口呢? (1 ...

  6. ubuntu 的挂起与休眠

    待机 计算机将目前的运行状态等数据存放在内存,关闭硬盘.外设等设备,进入等待状态.此时内存仍然需要电力维持其数据,但整机耗电很少.恢复时计算机从内存读 出数据,回到挂起前的状态,恢复速度较快.一般笔记 ...

  7. PS 图像调整算法——色调分离

    色调分离的原理就是将R, G, B每个通道 0-255 的色调区间进行强制划分到给定的区间里去,所以色调会合并,最终的图像看起来颜色就是一块一块的. clc; clear all; close all ...

  8. SQLite数据库中多线程使用问题

    由于项目是接手之前的烂尾项目,经常被吐槽说界面卡半天,后来发现项目里的网络请求,数据库操作都是在主线程.将一些长时间的操作换到多线程或者异步之后后,用户交互是变的顺畅多了,可是经常出现莫名其妙的闪退, ...

  9. 高通Android display架构分析

    目录(?)[-] Kernel Space Display架构介绍 函数和数据结构介绍 函数和数据结构介绍 函数和数据结构介绍 数据流分析 初始化过程分析 User Space display接口 K ...

  10. Redis客户端ServiceStack.Redis的简单使用

    在nuget中下载ServiceStack.Redis,但是运行之后会出现一个问题: Exception: "Com.JinYiWei.Cache.RedisHelper"的类型初 ...