将 boost::beast::multibuffer 转换为 std::istream

Convert boost::beast::multibuffer to std::istream

提问人:Стас 提问时间:6/13/2023 更新时间:6/13/2023 访问量:83

问:

我正在从方法中获取对象。然后,我想像这样从中解析json内容:boost::beast::multibufferhttp::response<http::dynamic_body>::body()

boost::property_tree::read_json(requestBodyStream, propertyTree);

我应该使用 and 获取,还是可以在不花费太多内存来复制缓冲区内容的情况下进行?boost::beast::buffers_to_stringstd::stringstreamrequestBodyStream

json c++17 stringstream boost-beast

评论


答:

1赞 sehe 6/13/2023 #1

一般来说,不要对具体的实现进行编程,而是对概念进行编程。在这里,文件dynamic_body

此正文使用 a 作为基于内存的容器来保存消息有效负载。使用此正文类型的消息可以序列化和分析。DynamicBuffer

你不需要这个概念,因为无论如何你都会完全在内存中使用这个概念,但如果你这样做了,你会像这样去做:

net::streambuf sb;
sb.commit(net::buffer_copy(sb.prepare(body.size()), body.cdata()));

std::istream is(&sb);
ptree doc;
read_json(is, doc);

在 Coliru 上观看直播

#include <boost/asio.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>

#include <boost/beast/http.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
namespace net = boost::beast::net;
namespace http = boost::beast::http;
using boost::property_tree::ptree;

int main() {
    net::posix::stream_descriptor input(net::system_executor{}, 0); // stdin

    http::response<http::dynamic_body> res;
    {
        net::streambuf readbuf;
        http::read(input, readbuf, res);
    }

    auto& body = res.body();

    net::streambuf sb;
    sb.commit(net::buffer_copy(sb.prepare(body.size()), body.cdata()));

    std::istream is(&sb);
    ptree doc;
    read_json(is, doc);

    write_json(std::cout << "Parsed body: ", doc);
}

它读取来自 stdin 的示例响应,让我们使用

HTTP/1.1 200 OK
Content-Length: 50

{"this":{"is":[1,2,3], "a":"sample"}, "object":42}

这样:

g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp && ./a.out <<< $'HTTP/1.1 200 OK\r\nContent-Length: 50\r\n\r\n{\"this\":{\"is\":[1,2,3], \"a\":\"sample\"}, \"object\":42}'

指纹

Parsed body: {
    "this": {
        "is": [
            "1",
            "2",
            "3"
        ],
        "a": "sample"
    },
    "object": "42"
}

然而

现在我们已经回答了这个问题,让我们添加上下文:

  • 不要使用 Boost 属性树(除非您需要属性树。提示:你没有)。查看输出:属性树不是 JSON 库

  • 除非您需要,否则不要使用动态身体。在这种情况下,您将在内存中读取整个消息,将其复制到内存中(以转换为流式处理),使用区域设置感知的 istream(慢速)从中读取消息,结果在内存中作为另一个副本存在。

相反,请使用最简单的模型并使用 JSON 库,例如,您知道,Boost.JSON

在 Coliru 上直播

#include <boost/asio.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>

#include <boost/beast/http.hpp>
#include <boost/json/src.hpp> // for header-only
#include <iostream>
namespace net  = boost::beast::net;
namespace http = boost::beast::http;
namespace json = boost::json;

int main() {
    net::posix::stream_descriptor input(net::system_executor{}, 0); // stdin

    http::response<http::string_body> res;
    {
        net::streambuf readbuf;
        http::read(input, readbuf, res);
    }

    auto doc = json::parse(res.body());
    std::cout << "Parsed body: " << doc << "\n";
}

它代码更少,效率更高,最重要的是,正确处理 JSON!

评论

0赞 Стас 6/13/2023
谢谢!不知道)