【问题标题】:Using stream to treat received data使用流处理接收到的数据
【发布时间】:2020-06-09 02:39:05
【问题描述】:

我正在从套接字接收消息。 套接字封装在一个标头(基本上是消息的大小)和一个作为 crc 的页脚(一种检查消息是否未损坏的代码)中

所以,布局类似于:

size (2 bytes) | message (240 bytes) | crc (4 byte)

我写了operator>>

operator>> 如下:

std::istream &operator>>(std::istream &stream, Message &msg) {
    std::int16_t size;
    stream >> size;
    stream.read(reinterpret_cast<char*>(&msg), size);

    // Not receive enough data
    if (stream.rdbuf()->in_avail() < dataSize + 4) {
        stream.setstate(std::ios_base::failbit);
        return stream;
    }

    std::int16_t gotCrc;
    stream >> gotCrc;

    // Data not received correctly
    if(gotCrc != computeCrc(msg)) {
        stream.setstate(std::ios_base::failbit);
    }
    return stream;
}

消息可以逐字节到达,也可以完全到达。我们甚至可以一次收到多条消息。

基本上,我所做的是这样的:

struct MessageReceiver {
    std::string totalDataReceived;
    void messageArrived(std::string data) {
        // We add the data to totaldataReceived
        totalDataReceived += data;

        std::stringbuf buf(totalDataReceived);
        std::istream stream(&buf);
        std::vector<Message> messages(
            std::istream_iterator<Message>(stream), 
            std::istream_iterator<Message>{});
        std::for_each(begin(messages), end(messages), processMessage);
        // +4 for crc and + 2 for the size to remove
        auto sizeToRemove = [](auto init, auto message) {return init + message.size + 4 + 2;};
        // remove the proceed messages
        totalDataReceived.remove(accumulate(begin(messages), end(messages), 0, sizeToRemove);
    }
};

所以基本上,我们接收数据,我们将其插入到接收到的数据的总数组中。我们对它进行流式传输,如果我们至少收到一条消息,我们会将其从缓冲区 totalDataReceived 中删除。

但是,我不确定这是否是好方法。实际上,当计算错误的 crc 时,此代码不起作用...(未创建消息,因此我们不会对其进行迭代)。所以每次,我都会尝试阅读带有错误 crc 的消息...

我该怎么做?我无法将所有数据保留在totalDataReceived 中,因为在执行生命周期内我会收到很多消息。

我应该实现自己的streambuf吗?

【问题讨论】:

    标签: c++ stream istream istream-iterator


    【解决方案1】:

    我发现你想要创建的是一个类似于 std::istream 的类。当然你可以选择创建自己的类,但出于某些原因我更喜欢实现 std::streambuf。

    首先,使用您的类的人习惯于使用它,因为如果您继承并实现 std::streambuf 和 std::istream,它的作用与 std::istream 相同。

    其次,您不需要创建额外的方法,也不需要覆盖运算符。它们已经在 std::istream 的类级别中准备好了。

    实现 std::streambuf 所要做的就是继承它,覆盖 underflow() 并使用 setg() 设置 get 指针。

    【讨论】:

    • 您好,感谢您的回答。我不是在创建一个像 istream 一样的类。我正在创建一个可以通过 `operator>>` 流式传输的类。所以我需要为 Message 类创建 `operator>>`。问题是 `operator>>` 可能会失败。如果它失败了,我该如何正确处理这样的事情:)。
    • 你好,安托万。如果您可以通过调用 istream::fail() 来检查的 streambuf 中没有足够的数据,则 std::istream 的 Operator>> 可能会失败。您可以检查 istream 的故障位并在从 Message 中检索 size 和 gotCrc 后继续。希望对您有所帮助。
    • 或者,如果消息的大小是固定的,你可以在从socket完全接收到246字节后开始使用operator>>。此外,不得有字节序不匹配。
    猜你喜欢
    • 2020-11-16
    • 2012-07-26
    • 2011-05-22
    • 1970-01-01
    • 2014-07-04
    • 1970-01-01
    • 2012-11-19
    • 2015-12-27
    • 1970-01-01
    相关资源
    最近更新 更多