通过野兽网络套接字发送二进制数据(在 C++ 中)

Posted

技术标签:

【中文标题】通过野兽网络套接字发送二进制数据(在 C++ 中)【英文标题】:Sending binary data through beast web-socket (in C++) 【发布时间】:2018-12-26 13:13:18 【问题描述】:

我想通过 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:WebSocket 流在两个端点都正常关闭

问题 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));
    

【问题讨论】:

尊重他人时间的一个好方法是遵循 Beast 文档中关于熟悉 Asio 的说明。这些问题与 Beast 无关。 嗨@VinnieFalco,我知道向新手教授这些概念(您已经掌握)可能会感觉很麻烦。我可以理解我的问题可能会偏离轨道。不过,我真诚地感谢您的帮助。今后我会尽量限制我的帖子。 PS:我只是一个试图在科技发达的世界中生存的菜鸟。 【参考方案1】:

答案 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#beast.using_websocket.control_frames.close_frames

"在读操作过程中收到关闭帧时,实现会自动响应关闭帧,然后在返回之前关闭底层连接。在这种情况下,读操作将完成并出现代码错误::已关闭。这向调用者表明连接已完全关闭。"

答案 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。否则每走一步都会遇到障碍。

【讨论】:

我已根据您的建议更新了问题。通过这些更新,程序没有到达“优雅”关闭连接的位置。相反,它以值-1 退出。调用函数是否正确编写? ws_.binary(true); 我已经更新了帖子。请看一看。 (net::buffer(binarydata,sizeof(binarydata)) 现在程序退出值0【参考方案2】:

您不能使用string 来存储二进制数据,将char data[]int lengthstd::vector&lt;char&gt; 一起使用。

一旦二进制文件中没有行,就不应使用getline() 读取二进制数据。

你可以使用类似的东西:

std::ifstream f("/home/rohan/TestFile.pcm", std::ios::binary);
std::vector<char> v(std::istreambuf_iterator<char>f, );

【讨论】:

我已经更新了帖子。正如你所见,我已经做出了改变。前面的文件读取方式我省略了(不正确的)。感谢您的指正。有没有办法查看binarydata 是否保存二进制数据? “保存二进制数据”是什么意思?任何数据都可以是二进制的,但不能是任何文本。所以无论binarydata 中有什么,它都是二进制数据。有时您可以假设数据是文本,但它们并不严格并且取决于可能的文本编码。 感谢您的澄清 :) std::string 不仅能够保存二进制数据,包括空值。 我已经使用 char 数组来获取二进制数据。您可以在更新后的帖子中查看我是如何读取二进制文件的。这对我有用。

以上是关于通过野兽网络套接字发送二进制数据(在 C++ 中)的主要内容,如果未能解决你的问题,请参考以下文章

通过 tcp 套接字发送十六进制值

将二进制数据从 QML 传递到 C++

从 iOS 到 WebSockets 的二进制数据

套接字编程/通过无线发送二进制图像数据

python套接字接收二进制数据

如何通过套接字发送/接收二进制数据?