使用流处理接收到的数据

问题描述 投票:0回答:1

我正在从套接字接收消息。套接字封装在标题(基本上是消息的大小)和页脚(即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个回答
0
投票

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

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

第二,您不需要创建额外的方法,也不需要重写运算符。他们已经在std :: istream的课程级别中准备好了。

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

© www.soinside.com 2019 - 2024. All rights reserved.