通过 beast web-socket 发送二进制数据(在 C++ 中)
Sending binary data through beast web-socket (in C++)
我想通过 websocket 连接将二进制音频数据发送到 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 websocket上发送数据(握手后)我已经按照这个套路做了
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: The WebSocket stream was gracefully closed at both endpoints
问题2:数据是否按预期正确运行?如何检查? (预期:See this link)
如何在不发送关闭命令的情况下关闭 websocket?
更新:
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));
}
答案一:
关于问题的 websocket 部分,您应该确保通过调用 websocket::stream::binary(true)
发送二进制消息。参见:
答案二:
"When a close frame is received during a read operation, the implementation will automatically respond with a close frame and then shut down the underlying connection before returning. In this case, the read operation will complete with the code error::closed. This indicates to the caller that the connection has been closed cleanly."
答案 3(已更新)
您写道:
vector<char> binarydata(istreambuf_iterator<char {infile}, {});
您正在使用局部变量作为异步操作的缓冲区。调用者负责确保缓冲区的生命周期至少延长到调用完成处理程序为止。您的代码产生未定义的行为。
Beast 文档明确说明了这一点:
"This library is for programmers familiar with Boost.Asio. Users who wish to use asynchronous interfaces should already know how to create concurrent network programs using callbacks or coroutines."
(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}, {});
我想通过 websocket 连接将二进制音频数据发送到 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 websocket上发送数据(握手后)我已经按照这个套路做了
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: The WebSocket stream was gracefully closed at both endpoints
问题2:数据是否按预期正确运行?如何检查? (预期:See this link)
如何在不发送关闭命令的情况下关闭 websocket?
更新:
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));
}
答案一:
关于问题的 websocket 部分,您应该确保通过调用 websocket::stream::binary(true)
发送二进制消息。参见:
答案二:
"When a close frame is received during a read operation, the implementation will automatically respond with a close frame and then shut down the underlying connection before returning. In this case, the read operation will complete with the code error::closed. This indicates to the caller that the connection has been closed cleanly."
答案 3(已更新)
您写道:
vector<char> binarydata(istreambuf_iterator<char {infile}, {});
您正在使用局部变量作为异步操作的缓冲区。调用者负责确保缓冲区的生命周期至少延长到调用完成处理程序为止。您的代码产生未定义的行为。
Beast 文档明确说明了这一点:
"This library is for programmers familiar with Boost.Asio. Users who wish to use asynchronous interfaces should already know how to create concurrent network programs using callbacks or coroutines."
(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}, {});