Асинхронная обработка потокового HTTP с boost :: beast

Я реализую клиента, который получает доступ к конечной точке REST, а затем начинает обработку SSE поток и мониторинг событий по мере их возникновения. Для этого я использую Boost :: Beast версии 124 с Boost 1.63 и пытаюсь использовать async_read_some постепенно читать тело ответа.

Вот мой код до сих пор:

namespace http = boost::beast::http;

http::response_parser<http::string_body> sse_client::m_parser;
http::response<http::string_body> sse_client::m_response;
boost::beast::flat_buffer m_buffer;

void sse_client::monitor_sse()
{
http::request<http::empty_body> req{http::verb::get, m_target, 11};
req.set(http::field::host, m_host);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
req.set(http::field::accept, "text/event-stream");
http::async_write(m_socket, req,
std::bind(
&sse_client::process_sse,
shared_from_this(),
std::placeholders::_1,
std::placeholders::_2));
}

void sse_client::process_sse(boost::system::error_code ec, std::size_t byte_count)
{
http::read_header(m_socket, m_buffer, m_parser);
http::async_read_some(m_socket, m_buffer, m_parser,
std::bind(
&sse_client::read_event,
shared_from_this(),
std::placeholders::_1));
}

void sse_client::read_event(boost::system::error_code ec)
{
// TODO: process event
http::async_read_some(m_socket, m_buffer, m_parser,
std::bind(
&sse_client::read_event,
shared_from_this(),
std::placeholders::_1));
}

Мои вопросы:

  1. Это правильный подход для этого конкретного случая использования?
  2. Есть ли более подходящий тип для использования с response_parser а также response чем http::string_body?
  3. Когда read_event вызывается обработчик, как он получает доступ к содержимому, полученному async_read_some? Должен ли он быть извлечен из буфера?

2

Решение

Сначала я отвечу на ваши вопросы, а затем объясню.

  1. Да, вы хотите прочитать заголовок и затем вызывать read_some (или читать, см. Ниже), пока парсер не вернет true из is_complete (). Однако в вашем коде я заметил, что вы смешиваете синхронные и асинхронные вызовы (read_header и async_read_some). Было бы лучше придерживаться только одной модели, а не смешивать их.

  2. Для ваших целей вы, вероятно, захотите buffer_body вместо string_body. В документации есть пример, который показывает, как это сделать (http://www.boost.org/doc/libs/1_66_0/libs/beast/doc/html/beast/using_http/parser_stream_operations/incremental_read.html)

  3. «Буфер», на который вы ссылаетесь, — это аргумент динамического буфера, переданный операции потока HTTP. Хотя этот буфер будет хранить данные сообщения, приложение не должно проверять его. Этот буфер используется для хранения дополнительных данных после конца текущего сообщения, которые может прочитать потоковый алгоритм (это объясняется в http://www.boost.org/doc/libs/1_66_0/libs/beast/doc/html/beast/using_http/message_stream_operations.html#beast.using_http.message_stream_operations.reading). Вы получите доступ к содержимому, проверив тело сообщения при использовании buffer_body

http :: response_parser :: get () предоставит вам доступ к прочитанному сообщению.

Лучшее решение для вас — это использовать buffer_body, как в примере, предоставить область памяти для указания на нее, а затем вызвать read или async_read в цикле. Каждый раз, когда буфер заполнен, чтение вернется с ошибкой beast::http::error::need_buffer, что указывает на необходимость дальнейших звонков.

Надеюсь это поможет!

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]