为什么我的Protobuf类可以解析由其他Protobuf类串联的字符串

Why my Protobuf class can parse a string serialized by an other Protobuf class

本文关键字:Protobuf 其他 字符串 我的 可以解 为什么      更新时间:2023-10-16

我试图知道我在TCP插座中获得的软件包,因此我使用ProtoBuf。但是当我SerializeToString我的第一个Protobuf类时,其他Protobuf类的ParseFromString返回true。

这两个类别是不同的

这是我的.proto

syntax = "proto3";
package protobuf;
message Message
{
    string content = 1;
}
message Player
{
    int32 id = 1;
    string name = 2;
}

这是我的C 代码

auto messageProto = new protobuf::Message;
messageProto->set_content("Hello");
std::string data;
messageProto->SerializeToString(&data);
protobuf::Player player;
if (player.ParseFromString(data))
{
    qDebug() << "parse player";
}
protobuf::Message message2;
if (message2.ParseFromString(data))
{
    qDebug() << "parse message";
}

输出:

parse player
parse message

为什么?

我建议解决多个有效载荷问题的建议:

syntax = "proto3";
package protobuf;
message RenameMe // the outer payload wrapper
{
  oneof payload
  {
    Foo foo = 1;
    Bar bar = 2;
  }
}
message Foo // one type of content
{
    string content = 1;
}
message Bar // another type of content
{
    int32 id = 1;
    string name = 2;
}

现在,您可以将所有内容都视为RenameMe(命名很难!(,并检查payload歧视的联合枚举以查看如何解释数据。然后分别访问foobar

这种方法清晰,明显,并且很容易且有效地扩展到其他消息类型中。可以用许多编程语言使用switch实施测试。这种样式在某些环境中的多态性也很好地效果很好 - 例如,在c#的Protobuf -net中,可以通过以下方式序列化/进行序列化:

[ProtoContract, ProtoInclude(1, typeof(Foo)), ProtoInclude(2, typeof(Bar))]
abstract class RenameMe {}
[ProtoContract]
class Foo : RenameMe {
  [ProtoMember(1)] public string Content {get;set;}
}
[ProtoContract]
class Bar : RenameMe {
  [ProtoMember(1)] public int Id {get;set;}
  [ProtoMember(2)] public string Name {get;set;}
}

编辑:那么,现在,它是最好的方法吗?

syntax = "proto3";
message Header
{
    oneof payload
    {
        Message message = 1;
        Player player = 2;
    }
}
message Message
{
    string content = 1;
}
message Player
{
    int32 id = 1;
    string name = 2;
}

写作时:

void SocketManager::sendData(Player& player)
{
    Header header;
    header.set_allocated_player(&player);
    write(header);
}
void SocketManager::sendData(Message& message)
{
    Header header;
    header.set_allocated_message(&message);
    write(header);
}
// etc... for each kind of message

我阅读时:

void read(const std::string& data)
{
    protobuf::Header header;
    header.ParseFromString(data);
    switch (header.payload_case())
    {
    case protobuf::Header::kMessage:
        emit messageProtoReceived(header.message());
        break;
    case protobuf::Header::kPlayer:
        emit playerProtoReceived(header.player());
        break;
    case protobuf::Header::PAYLOAD_NOT_SET:
        qDebug() << "Error, the payload isn't set, please create a header with a payload";
        break;
    }
}
相关文章: