Получение больших двоичных данных через Boost :: Beast websocket

Я пытаюсь получить большой объем данных, используя boost :: beast :: websocket, питаемый другим boost :: beast :: websocket. Обычно эти данные отправляются в подключенный браузер, но я хотел бы настроить чисто C ++ модульный тест, проверяющий определенные компоненты трафика. Я установил автоматическую фрагментацию на true от отправителя с максимальным размером 1 МБ, но после нескольких сообщений получатель выплевывает:

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"

Теперь я не должен ожидать, что полностью разработанный и хорошо поддерживаемый браузер будет демонстрировать те же характеристики, что и мой, возможно, плохо спроектированный модульный тест, а это не так. У браузера нет проблем с чтением сообщений размером 25 МБ через веб-узел. С другой стороны, мой 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). Будет ли это правильным подходом для всегда открытого веб-сокета, который может отправлять довольно большие сообщения? Должен ли я послать клиенту какой-нибудь индикатор того, что сообщение действительно готово? И столкнулся бы я с проблемой превышения лимита буфера, используя этот подход?


person nhruch    schedule 15.04.2021    source источник


Ответы (1)


Если ваш шаблон использования исправлен:

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

А потом, в частности

    callback(data);

Тогда будет вообще бесполезно читать по блокам, так как вы все равно будете выделять ту же память. Вместо этого вы можете увеличить локально настроенный лимит:

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

Значение по умолчанию - 16 miB (при повышении 1,75).

Примечание

Вероятно, вы также можете использовать ws.got_binary(), чтобы определить, было ли последнее полученное сообщение двоичным или нет.

person sehe    schedule 15.04.2021
comment
Это всегда единственный вариант, который вы как-то упускаете из виду ... Спасибо за это. - person nhruch; 17.04.2021