【问题标题】:How can I convert serialized data in boost::beast to a string so that I could process it in a FIFO manner?如何将 boost::beast 中的序列化数据转换为字符串,以便以 FIFO 方式处理它?
【发布时间】:2019-04-10 10:14:41
【问题描述】:

我有一个客户端应用程序,我需要从服务器接收 http“长时间运行的请求”。我发送一个命令,得到响应的头部后,我只需要接收由\r\n分隔的json数据,直到连接终止。

我设法调整boost beast client example 来发送消息并接收标头并解析它并接收来自服务器的响应。但是,我未能找到一种方法来序列化数据以便处理 json 消息。

可以在this relay example 中找到最接近该问题的演示。在那个例子中(p 是一个解析器,sr 是一个序列化器,input 是一个套接字输入流,output 是一个套接字输出流),在读取了 http 头之后,我们有一个循环不断地读取来自服务器:

do
{
    if(! p.is_done())
    {
        // Set up the body for writing into our small buffer
        p.get().body().data = buf;
        p.get().body().size = sizeof(buf);

        // Read as much as we can
        read(input, buffer, p, ec);

        // This error is returned when buffer_body uses up the buffer
        if(ec == error::need_buffer)
            ec = {};
        if(ec)
            return;

        // Set up the body for reading.
        // This is how much was parsed:
        p.get().body().size = sizeof(buf) - p.get().body().size;
        p.get().body().data = buf;
        p.get().body().more = ! p.is_done();
    }
    else
    {
        p.get().body().data = nullptr;
        p.get().body().size = 0;
    }

    // Write everything in the buffer (which might be empty)
    write(output, sr, ec);

    // This error is returned when buffer_body uses up the buffer
    if(ec == error::need_buffer)
        ec = {};
    if(ec)
        return;
}
while(! p.is_done() && ! sr.is_done());

这里有一些我不明白的地方:

  1. 我们已经读完了标题。为什么我们需要 boost beast 而不是 boost asio 来读取原始 tcp 消息?当我尝试这样做时(同时使用 async_read/async_read_some),我得到了一个大小为零的无限读取。
  2. parser 的文档说(在页面末尾)每条消息都需要一个新实例,但我在示例中没有看到。
  3. 由于 tcp 消息读取不起作用,有没有办法将解析器/序列化器数据转换为某种字符串?甚至以先进先出的方式将其写入文本文件,以便我可以使用一些 json 库来处理它?我不想像示例那样使用另一个套接字。

函数boost::beast::buffers() 无法为解析器和序列化程序编译,并且解析器没有消费函数,序列化程序的消费似乎是针对消息的特定 http 部分,如果我这样做会触发一个断言对于body()

除此之外,我还未能从解析器和缓冲区中获取一致的数据块,使用老式的std::copy。我似乎不明白如何将数据组合在一起以获取数据流。在接收数据的任何时候使用.consume() 使用缓冲区会导致need buffer 错误。

我非常感谢有人解释所有这些应该如何协同工作的逻辑。

【问题讨论】:

    标签: c++ http boost boost-asio boost-beast


    【解决方案1】:

    buf 在哪里?你可以直接读入std::string。调用string.resize(N),将buffer_body::value_type中的指针和大小设置为string.data()string.size()

    【讨论】:

    • IIUYC,它唯一能做的改变就是用string替换buf。但这不是我遇到麻烦的地方。序列化程序后我遇到了麻烦。我不想将序列化程序写入套接字(如我从 http_relay 复制的示例所示),我希望它转到字符串/视图。您之前提到过分块,这是一个合理的问题。特别是,在我将任何内容转换为字符串的所有尝试中,我都有重复的部分数据。能否请您编写一些将write(output, sr, ec); 替换为将sr 转换为字符串的代码的小sn-p 代码?
    • 您想将 HTTP 消息转换为字符串吗?使用operator<<std::stringstream
    • 谢谢,维尼。我想我现在明白它是如何工作的了。我不需要序列化程序。我误解了文档。序列化程序不是必需的,因为我不想提交到套接字。我只需要解析器。一旦我在解析器模板参数中使用了string_body,一切都变得简单并且一切正常。剩下的唯一问题是,由于它被分块并且蒸汽永远不会结束,解析器内容只会无限期地增长。有没有办法清除/使用它的字符串内容? (除了重新创建连接)
    • 我发现的唯一明确的功能是针对单个身体对象,而不是解析器中的所有内容。一个问题是,由于某种原因,在body() 中,所有终结符\r\n 都不存在。我能够通过使用payload_size() 来规避这个问题,我在其中读取了一个正文,如果可解析,则使用 json 解析它,然后清除 body() 字符串。不知道为什么终结者正在消失。只要不合并消息/读取回调,我就可以忍受,否则会破坏 json 解析。如果我做错了,请告诉我。最好的。
    • 您不会看到分块的编码分隔符,因为 Beast 的解析器会在将数据附加到字符串之前删除它们。正如我已经说过的,如果您想逐步解析永无止境的响应,请使用buffer_body
    猜你喜欢
    • 1970-01-01
    • 2020-04-30
    • 2020-10-04
    • 1970-01-01
    • 2016-01-08
    • 2011-08-19
    • 1970-01-01
    • 2016-03-16
    • 1970-01-01
    相关资源
    最近更新 更多