Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使用boost::iostreams:filtering\u istream解压boost::asio::streambuf中的数据?_C++_Boost_Boost Asio_Zlib_Boost Iostreams - Fatal编程技术网

C++ 如何使用boost::iostreams:filtering\u istream解压boost::asio::streambuf中的数据?

C++ 如何使用boost::iostreams:filtering\u istream解压boost::asio::streambuf中的数据?,c++,boost,boost-asio,zlib,boost-iostreams,C++,Boost,Boost Asio,Zlib,Boost Iostreams,我正在尝试解压缩从boost asio套接字接收的zlib压缩数据。(版本1.64.0) 我使用boost::asio::streambuf作为接收缓冲区,使用boost::iostreams::filtering\u istream解压。 如果我一次发送一个压缩的数据,我的代码就会像我预期的那样工作。但是,如果我发送一个压缩数据,将其分成5字节的块,代码就不会像我预期的那样工作 compressed data: 78 9c f3 48 cd c9 c9 57 28 cf 2f ca 49 01

我正在尝试解压缩从boost asio套接字接收的zlib压缩数据。(版本1.64.0) 我使用
boost::asio::streambuf
作为接收缓冲区,使用
boost::iostreams::filtering\u istream
解压。 如果我一次发送一个压缩的数据,我的代码就会像我预期的那样工作。但是,如果我发送一个压缩数据,将其分成5字节的块,代码就不会像我预期的那样工作

compressed data: 78 9c f3 48 cd c9 c9 57 28 cf 2f ca 49 01 00 18 ab 04 3d 
78 9c f3 48 cd c9 c9 57 28 cf 2f ca 49 01 00 18 ab 04 3d 
sbuf.size():19
<<< try decompress >>>
  `is` has some data.
  read_size:11
  decompressed data: Hello world
<<< decompress loop out >>>
我创建一个压缩数据,如下所示:

auto str = prepare_compressed_data("Hello world");
// Prepare decompressing istream
boost::asio::streambuf sbuf;
boost::iostreams::filtering_istream is;
is.push(boost::iostreams::zlib_decompressor());
is.push(sbuf);
数据如下:

78 9c f3 48 cd c9 c9 57 28 cf 2f ca 49 01 00 18 ab 04 3d
(Length is 19)
我将过滤流设置为解压缩,如下所示:

auto str = prepare_compressed_data("Hello world");
// Prepare decompressing istream
boost::asio::streambuf sbuf;
boost::iostreams::filtering_istream is;
is.push(boost::iostreams::zlib_decompressor());
is.push(sbuf);
以下是网络发送-接收模拟代码:

// Network (asio socket send-receive) emulation
auto str_it = str.begin();
auto rest = str.size();
while (rest != 0) {
    auto copy_size = std::min(rest, send_size); // send_size is 5

    // Emulate receive
    //   In actual code, it is `socket.read_some(mbuf)`
    //   and its return value is `copy_size`.

    auto mbuf = sbuf.prepare(copy_size);
    char* p = boost::asio::buffer_cast<char*>(mbuf);
    std::copy(str_it, str_it + copy_size, p);
    sbuf.commit(copy_size);
    hexdump(std::string(boost::asio::buffer_cast<char const*>(sbuf.data()), sbuf.size()));
    std::cout << "sbuf.size():" << sbuf.size() << std::endl;
    { // decompress
        std::cout << "<<< try decompress >>>" << std::endl;
        while (is) {
            std::cout << "  `is` has some data." << std::endl;
            char buf[buf_size + 1] = { '\0' };
            is.read(buf, buf_size);
            std::size_t read_size = is.gcount();
            std::cout << "  read_size:" << read_size << std::endl;
            std::cout << "  decompressed data: " << buf << std::endl;

            // It seems that is.read() consumed 5 bytes data in underlying sbuf
            // even if is.gcount() returned 0.
        }
        std::cout << "<<< decompress loop out >>>" << std::endl;
    }
    rest -= copy_size;
    str_it += copy_size;
}
如果我一次复制
str
,我会得到我预期的结果

compressed data: 78 9c f3 48 cd c9 c9 57 28 cf 2f ca 49 01 00 18 ab 04 3d 
78 9c f3 48 cd c9 c9 57 28 cf 2f ca 49 01 00 18 ab 04 3d 
sbuf.size():19
<<< try decompress >>>
  `is` has some data.
  read_size:11
  decompressed data: Hello world
<<< decompress loop out >>>
压缩数据:78 9c f3 48 cd c9 c9 57 28 cf 2f ca 49 01 00 18 ab 04 3d
78 9c f3 48 cd c9 c9 57 28 cf 2f ca 49 01 00 18 ab 04 3d
sbuf.size():19
>
`他有一些数据。
阅读尺寸:11
解压数据:Hello world
>

当您阅读不完整的输入时,过滤流将发出EOF信号,并保持信号状态

解决此问题的最安全方法是暂时复制sbuf数据,并且在成功解压缩时仅
consume()
数据:

#include <sstream>
#include <string>
#include <iostream>
#include <iomanip>
#include <algorithm>

#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/zlib.hpp>

#include <boost/asio.hpp>

void hexdump(std::string const& buf) {
    for (std::string::const_iterator it = buf.begin(), end = buf.end();
         it != end;
         ++it) {
        std::cout
            << std::setw(2)
            << std::hex
            << std::setfill('0')
            << (static_cast<int>(*it) & 0xff)
            << ' ';
    }
    std::cout << std::dec << std::endl;
}

std::string prepare_compressed_data(std::string const& str) {
    std::stringstream sender;
    boost::iostreams::filtering_streambuf<boost::iostreams::input> out;
    out.push(boost::iostreams::zlib_compressor());
    out.push(sender);
    sender << str << std::flush;
    std::stringstream compressed;
    boost::iostreams::copy(out, compressed);
    return compressed.str();
}

int main() {
    auto str = prepare_compressed_data("Hello world");
    std::cout << "compressed data: ";
    hexdump(str);

    // Test settings
#if 0
    // send all at conce
    std::size_t const send_size = str.size();
#else
    // send 5 byte chunks
    std::size_t const send_size = 5;
#endif
    std::size_t const buf_size = 256;

    // Prepare decompressing istream
    boost::asio::streambuf sbuf;

    // Network (asio socket send-receive) emulation
    auto str_it = str.begin();
    auto rest = str.size();
    while (rest != 0) {
        auto copy_size = std::min(rest, send_size);

        // Emulate receive
        //   In actual code, it is `socket.read_some(mbuf)`
        //   and its return value is `copy_size`.

        auto mbuf = sbuf.prepare(copy_size);
        char* p = boost::asio::buffer_cast<char*>(mbuf);
        std::copy(str_it, str_it + copy_size, p);
        sbuf.commit(copy_size);

        hexdump(std::string(boost::asio::buffer_cast<char const*>(sbuf.data()), sbuf.size()));
        std::cout << "sbuf.size():" << sbuf.size() << std::endl;
        { // decompress
            std::cout << "<<< try decompress >>>" << std::endl;
            char buf[buf_size] = {};
            std::size_t read_size = 0;

            boost::iostreams::filtering_istream is;
            is.push(boost::iostreams::zlib_decompressor());
            std::stringstream ss(std::string(boost::asio::buffer_cast<char const*>(sbuf.data()), sbuf.size()));
            is.push(ss);

            while (is.read(buf, buf_size) || (read_size = is.gcount())) {
                std::cout << "  `is` has some data." << std::endl;
                std::cout << "  read_size:" << read_size << std::endl;
                (std::cout << "  decompressed data: ").write(buf, read_size) << std::endl;

                // It seems that is.read() consumed 5 bytes data in underlying sbuf
                // even if is.gcount() returned 0.
            }
            std::cout << "<<< decompress loop out >>>" << std::endl;
        }
        rest -= copy_size;
        str_it += copy_size;
    }
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
void hextump(std::string const&buf){
对于(std::string::const_迭代器it=buf.begin(),end=buf.end();
它!=结束;
++(it){
标准::cout

谢谢你的回答!似乎安全的方法是在收到所有压缩数据后解压?我理解正确吗?我直接编写了使用zlib的代码。我知道没有安全的方法使用boost::iostreams来执行等效的进程。对吗?