C++中从流读取带大小前缀Flatbuffers的正确实现范式咨询
C++ 从带大小前缀的流(如TCP)读取Flatbuffers的正确实现范式
错误的初始实现
一开始我尝试用以下代码提取消息:
while (true) { flatbuffers::Verifier v(buf.data(), buf.size()); if (v.VerifySizePrefixedBuffer<Message>(nullptr)) { const flatbuffers::uoffset_t off = flatbuffers::GetPrefixedSize(buf.data()); const auto msg = flatbuffers::GetSizePrefixedRoot<Message>(buf.data()); // 使用消息 buf.erase(buf.begin(), buf.begin() + 4 + off); } else { break; } }
问题分析
这段代码存在错误:VerifySizePrefixedBuffer会检查传入验证器的缓冲区大小等于大小前缀对应的总长度(前缀+消息体),而非“至少”等于。从verifier.h的源码可以看到:
Check(ReadScalar<uoffset_t>(buf_) == size_ - sizeof(uoffset_t))
这意味着如果缓冲区包含多条消息,验证器无法只检查第一条消息的有效性——它会因为缓冲区总长度大于单条消息长度而直接验证失败。
修正后的实现
需要先读取消息大小,再截取对应长度的缓冲区传入验证器:
while (buf.size() >= 4) { const flatbuffers::uoffset_t off = flatbuffers::GetPrefixedSize(buf.data()); flatbuffers::Verifier v(buf.data(), 4 + off); if (v.VerifySizePrefixedBuffer<Message>(nullptr)) { const auto msg = flatbuffers::GetSizePrefixedRoot<Message>(buf.data()); // 使用消息 buf.erase(buf.begin(), buf.begin() + 4 + off); } else { break; } }
疑问与解答
但这种方式似乎重复了验证器对前缀有效性的检查,请问这是否是Flatbuffers预期的用法?有没有更优的实现范式?
这就是Flatbuffers处理带大小前缀流的预期用法,不存在冗余问题:
- 先读取前缀是为了确定单条消息的完整长度,避免缓冲区包含多条消息或不完整消息导致验证失败;
VerifySizePrefixedBuffer除了检查前缀与缓冲区长度的匹配,还会验证Flatbuffer本身的结构合法性(比如偏移量是否有效、字段是否符合定义等),这是GetPrefixedSize无法完成的;- 若担心重复读取前缀,可手动先验证前缀合理性(比如是否为合法无符号数、是否超过缓冲区剩余长度),再调用验证器,示例如下:
while (buf.size() >= sizeof(flatbuffers::uoffset_t)) { auto prefix = flatbuffers::ReadScalar<flatbuffers::uoffset_t>(buf.data()); // 提前检查前缀合理性,过滤恶意或错误数据 if (prefix > buf.size() - sizeof(flatbuffers::uoffset_t)) { break; // 消息不完整或非法,等待更多数据 } flatbuffers::Verifier v(buf.data(), sizeof(flatbuffers::uoffset_t) + prefix); if (v.VerifySizePrefixedBuffer<Message>(nullptr)) { const auto msg = flatbuffers::GetSizePrefixedRoot<Message>(buf.data()); // 使用消息 buf.erase(buf.begin(), buf.begin() + sizeof(flatbuffers::uoffset_t) + prefix); } else { break; // 消息结构非法,终止处理 } }
总结来说,先读取前缀确定消息长度,再针对单条消息做验证,是处理流式Flatbuffers的标准流程。前缀读取与结构验证是两个独立环节,各自承担不同职责,不存在更优的“无重复”实现范式。
内容的提问来源于stack exchange,提问作者tchatow
相关产品推荐
相关产品推荐

