Отправка двоичных данных через веб-сокет beast (в C++)

Я хочу отправить двоичные аудиоданные в службу IBM watson STT через соединение через веб-сокет. Я успешно установил соединение и сейчас пытаюсь отправить данные в следующем формате:

{
  "action":"start",
  "content-type": "audio/l16;rate=44100"
}
<binary audio data>
{
  "action":"stop"
}

для этого: я читаю сырой аудио файл (extn .pcm), как показано ниже

#include <string>
#include <fstream>

ifstream fin;
string binarydata, bdataline;

fin.open("/home/rohan/TestFile.pcm", ios::binary | ios::in);

while (fin) {
    // Read a Line from File
    getline(fin, bdataline);
    binarydata = binarydata + bdataline;
}

Вопрос 1: Я не уверен, правильно ли я читаю двоичные данные. Должен ли тип данных binarydata быть string?

Далее, чтобы отправить данные на веб-сокет Boost (после рукопожатия), я следовал этой процедуре

void on_handshake(beast::error_code ec)
    {
         if(ec)
             return fail(ec, "handshake");

         // Send the Start message
         ws_.async_write(net::buffer("{\"action\":\"start\",\"content-type\": \"audio/l16;rate=44100\"}"), bind(&session::on_start, shared_from_this(), placeholders::_1));
    }

void on_start(beast::error_code ec)
    {
        if(ec)
            return fail(ec, "write:start");

        ws_.async_write(net::buffer(binarydata), bind(&session::on_binarysent, shared_from_this(), placeholders::_1));
    }

void on_binarysent(beast::error_code ec)
    {
        if(ec)
            return fail(ec, "write:Msg");

        ws_.async_write(net::buffer("{\"action\":\"stop\"}"), bind(&session::on_write, shared_from_this(), placeholders::_1));
    }


void on_write( beast::error_code ec) //,
    {
        if(ec)
            return fail(ec, "write:end");

        ws_.async_read(buffer_, bind(&session::on_start, shared_from_this(), placeholders::_1));
    }

Программа не показывает никаких выходных данных и завершает работу с

write: start: Поток WebSocket был изящно закрыт на обеих конечных точках

Вопрос 2: данные идут правильно, как ожидалось? Как это проверить? (ожидается: см. эту ссылку)

Как веб-сокет закрывается без отправки команды закрытия?

ОБНОВЛЕНО:

void on_start(beast::error_code ec)
    {
        if(ec)
            return fail(ec, "write:start");



ifstream infile("/home/rohan/TestFile.pcm", ios::in | ios::binary);
    streampos FileSize;

    if (infile) {
        // Get the size of the file
        infile.seekg(0, ios::end);
        FileSize = infile.tellg();
        infile.seekg(0, ios::beg);
    }
    char binarydata[(size_t)FileSize];
        ws_.binary(true);

        // Send binary data
        ws_.async_write(net::buffer(binarydata, sizeof(binarydata)), bind(&session::on_binarysent, shared_from_this(), placeholders::_1));
    }

2 ответа

Решение

Ответ 1:

Что касается части вопроса о websocket, вы должны убедиться, что вы отправляете двоичные сообщения, вызывая websocket::stream::binary(true), Увидеть:

https://www.boost.org/doc/libs/1_69_0/libs/beast/doc/html/beast/ref/boost__beast__websocket__stream/binary/overload1.html

Ответ 2:

От: https://www.boost.org/doc/libs/1_69_0/libs/beast/doc/html/beast/using_websocket/control_frames.html

"Когда закрытый кадр получен во время операции чтения, реализация автоматически ответит закрывающим кадром, а затем закроет основное соединение перед возвратом. В этом случае операция чтения завершится с кодом error::closed. Это указывает вызывающей стороне, что соединение было закрыто чисто."

Ответ 3 (Обновлено)

Вы написали:

vector<char> binarydata(istreambuf_iterator<char {infile}, {});

Вы используете локальную переменную в качестве буфера для асинхронной операции. Вызывающая сторона отвечает за то, чтобы время жизни буферов продолжалось как минимум до тех пор, пока не будет вызван обработчик завершения. Ваш код производит неопределенное поведение.

Документация Beast проясняет это:

"Эта библиотека для программистов, знакомых с Boost.Asio. Пользователи, которые хотят использовать асинхронные интерфейсы, уже должны знать, как создавать параллельные сетевые программы с использованием обратных вызовов или сопрограмм".

( https://www.boost.org/doc/libs/1_69_0/libs/beast/doc/html/beast/introduction.html)

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

Вы не можете использовать string для хранения двоичных данных используйте char data[] с int length или же std::vector<char> или что угодно.

Чтение двоичных данных не должно быть сделано с getline() как только в двоичных файлах нет строк.

Вы можете использовать что-то вроде:

std::ifstream f("/home/rohan/TestFile.pcm", std::ios::binary);
std::vector<char> v(std::istreambuf_iterator<char>{f}, {});
Другие вопросы по тегам