我正在从套接字接收消息。套接字封装在标题(基本上是消息的大小)和页脚(即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吗?
我发现您要创建的是一个类似于std :: istream的类。当然,您可以选择创建自己的类,但是出于某些原因,我更喜欢实现std :: streambuf。
首先,使用您的类的人们习惯于使用它,因为如果您继承并实现std :: streambuf和std :: istream,它的作用与std :: istream相同。
第二,您不需要创建额外的方法,也不需要重写运算符。他们已经在std :: istream的课程级别中准备好了。
实现std :: streambuf所要做的就是继承它,重写underflow()并使用setg()设置get指针。