Как я могу преобразовать сериализованные данные в boost :: beast в строку, чтобы я мог обрабатывать их в режиме FIFO?

У меня есть клиентское приложение, в котором мне нужно получать HTTP-запросы с длительным сроком выполнения от сервера. Я отправляю команду, и после получения заголовка ответа мне нужно просто получать данные json, разделенные \r\n, до тех пор, пока соединение не будет разорвано.

Мне удалось адаптировать boost beast пример клиента, чтобы отправить сообщение, получить заголовок, проанализировать его и получить ответы от сервера. Однако мне не удалось найти способ сериализации данных, чтобы я мог обрабатывать сообщения json.

Ближайшую демонстрацию проблемы можно найти в этот пример реле. В этом примере (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. Документация по парсеру говорит (в конце страницы), что новый экземпляр необходим для каждого сообщения, но я не вижу этого в примере.
  3. Поскольку чтение сообщений TCP не работает, есть ли способ преобразовать данные парсера / сериализатора в какую-то строку? Даже записать его в текстовый файл в стиле FIFO, чтобы я мог обработать его какой-нибудь json-библиотекой? Я не хочу использовать другой сокет, как в примере.

Функцию boost::beast::buffers() не удалось скомпилировать для парсера и сериализатора, а для парсера нет функции потребления, а потребление сериализатора, похоже, предназначено для определенных частей сообщения http, которые запускают assert, если я делаю это для body().

Кроме того, я также не смог получить согласованные порции данных из парсера и буфера с помощью старой школы std::copy. Кажется, я не понимаю, как объединить данные, чтобы получить поток данных. Использование буфера с .consume() в любой момент при получении данных приводит к ошибке need buffer.

Я был бы очень признателен, если бы кто-нибудь объяснил логику того, как все это должно работать вместе.


person The Quantum Physicist    schedule 10.04.2019    source источник


Ответы (1)


Где buf? Вместо этого вы можете читать прямо в std::string. Вызовите string.resize(N) и установите указатель и размер в buffer_body::value_type на string.data() и string.size().

person Vinnie Falco    schedule 10.04.2019
comment
IIUYC, единственное изменение, которое он внесет, - это заменить buf на string. Но тогда у меня проблемы не здесь. У меня проблемы после сериализатора. Вместо того, чтобы записывать сериализатор в сокет (как показано в примере, который я скопировал из http_relay), я бы хотел, чтобы он перешел в строку / представление. Вы упомянули о дроблении ранее, и это законное беспокойство. Тем более, что при всех моих попытках преобразовать что-либо в строку у меня повторялись части данных. Не могли бы вы написать небольшой фрагмент кода, который заменяет write(output, sr, ec); чем-то, что преобразует sr в строку? - person The Quantum Physicist; 11.04.2019
comment
Вы хотите преобразовать HTTP-сообщение в строку? Используйте operator<< до std::stringstream. - person Vinnie Falco; 11.04.2019
comment
Спасибо, Винни. Думаю, теперь я понимаю, как это работает. Мне не нужен сериализатор. Я неправильно понял документацию. Сериализатор не нужен, потому что я не хочу подчиняться сокету. Мне просто нужен был парсер. Как только я использовал string_body в параметре шаблона парсера, все стало легко и все заработало. Единственная оставшаяся проблема заключается в том, что, поскольку он разбит на части и поток никогда не заканчивается, содержимое парсера просто продолжает расти бесконечно. Есть ли способ очистить / использовать его строковое содержимое? (кроме восстановления связи) - person The Quantum Physicist; 11.04.2019
comment
Единственная понятная функция, которую я нашел, - это отдельные объекты тела, а не все в анализаторе. Проблема в том, что по какой-то причине в body() все терминаторы \r\n отсутствовали. Я смог обойти эту проблему, используя payload_size(), где я читал тело, анализировал его с помощью json, если его можно было проанализировать, а затем очищал строку body (). Понятия не имею, почему исчезают терминаторы. Я могу жить с этим до тех пор, пока обратные вызовы сообщений / чтения не будут объединены, иначе это саботирует синтаксический анализ json. Если я что-то делаю неправильно, дайте мне знать. Лучший. - person The Quantum Physicist; 11.04.2019
comment
Вы не увидите разделителей кодирования фрагментов, потому что синтаксический анализатор Beast удаляет их перед добавлением данных в строку. Как я уже сказал, используйте buffer_body, если вы хотите постепенно анализировать бесконечный ответ. - person Vinnie Falco; 12.04.2019
comment
Я сделаю это дальше. Теперь у меня есть рабочая отправная точка, где я могу оптимизировать все в полной мере и знать, чего ожидать. Еще раз спасибо и хорошего дня :-) - person The Quantum Physicist; 12.04.2019