通过 Boost::Beast websocket 接收大量二进制数据

Receiving large binary data over Boost::Beast websocket

我正在尝试使用 boost::beast::websocket 接收大量数据,由另一个 boost::beast::websocket 提供。通常,此数据会发送到连接的浏览器,但我想设置一个纯 C++ 单元测试来验证流量的某些组件。我将最大大小为 1MB 的发件人的自动分片设置为 true,但在几条消息之后,接收者吐出:

Read 258028 bytes of binary
Read 1547176 bytes of binary
Read 168188 bytes of binary
"Failed read: The WebSocket message exceeded the locally configured limit"

现在,我不应该期望一个完全开发和良好支持的浏览器应该表现出与我可能架构不佳的单元测试相同的特征,而事实并非如此。浏览器可以通过 websocket 读取 25MB 的消息没有问题。另一方面,我的 boost::beast::websocket 达到了极限。

所以在我陷入困境之前,我想看看是否有人对此有任何想法。我的阅读部分如下所示:

void on_read(boost::system::error_code ec, std::size_t bytes_transferred)
{
    boost::ignore_unused(bytes_transferred);

    if (ec)
    {
        m_log.error("Failed read: " + ec.message());
        // Stop the websocket
        stop();
        return;
    }

    std::string data(boost::beast::buffers_to_string(m_buffer.data()));

    // Yes I know this looks dangerous. The sender always sends as binary but occasionally sends JSON 
    if (data.at(0) == '{')
        m_log.debug("Got message: " + data);
    else
        m_log.debug("Read " + utility::to_string(m_buffer.data().buffer_bytes()) + " of binary data");

    // Do the things with the incoming doata
    for (auto&& callback : m_read_callbacks)
        callback(data);

    // Toss the data
    m_buffer.consume(bytes_transferred);

    // Wait for some more data
    m_websocket.async_read(
        m_buffer,
        std::bind(
            &WebsocketClient::on_read,
            shared_from_this(),
            std::placeholders::_1,
            std::placeholders::_2));
}

我在一个单独的示例中看到,您可以执行 for/while 循环读取一些数据,而不是执行异步读取,直到消息完成 (https://www.boost.org/doc/libs/1_67_0/libs/beast/doc/html/beast/using_websocket/send_and_receive_messages.html)。对于可以发送一些相当大的消息的始终打开的 websocket,这是正确的方法吗?我是否必须向客户发送一些指示消息确实已完成?我会 运行 使用这种方法解决超出缓冲区限制的问题吗?

如果您的使用模式是固定的:

std::string data(boost::beast::buffers_to_string(m_buffer.data()));

然后,特别是

    callback(data);

那么按块读取将毫无用处,因为无论如何您都将分配相同的内存。相反,您可以 raise the "locally configured limit":

ws.read_message_max(20ull << 20); // sets the limit to 20 miB

默认值为 16 miB(截至 boost 1.75)。

旁注

您或许还可以使用 ws.got_binary() 来检测收到的最后一条消息是否为二进制。