【问题标题】:Proto2 encode/decode issues after adding new message添加新消息后的 Proto2 编码/解码问题
【发布时间】:2021-11-17 23:44:19
【问题描述】:

我对协议缓冲区还很陌生,但一直在尝试将它们作为通过 MQTT 发送数据的一种方式来学习。到目前为止,我已经很好地创建了 proto 消息并为 python 运行时编译它们,直到我开始注意到我的 protobufs 版本之间的不兼容。

当我向服务器端原型定义添加消息类型(不更改现有消息/字段)而不更新客户端原型定义时,解码发送到服务器的消息会给我带来不确定的结果。

下面是我所说的一个例子:

客户端原型:

message Wrapper {
    optional uint32 id = 1;
    optional string name = 2;
    oneof payload {
        Event event = 3;
        Command command = 4;
    }
}

message Event {
    uint32 event_id = 1;
    oneof event_payload {
        LoginEvent login_event = 2;
        LogoffEvent logoff_event = 3;
    }
}

服务器原型:

message Wrapper {
    optional uint32 id = 1;
    optional string name = 2;
    oneof payload {
        Event event = 3;
        Command command = 4;
    }

message Event {
    uint32 event_id = 1;
    oneof event_payload {
        LoginEvent login_event = 2;
        LogoffEvent logoff_event = 3;
        NewUserEvent new_user_event = 4;
    }
}

我将编码并从客户端发送一条消息:

message Wrapper {
    id = 12345;
    name = John;
    event = {
        login_event = ...
    }
}

并将在服务器上解码消息并获取:

message Wrapper {
    id = 12345;
    name = John;
    event = {
        logoff_event = ...
    }
}

注意:解码后的消息类型不确定,消息之间会发生变化

有人可以解释为什么添加事件类型似乎会破坏解码吗?或者我应该遵循什么最佳实践来提高版本兼容性?提前致谢!

【问题讨论】:

    标签: protocol-buffers version grpc decode encode


    【解决方案1】:

    可能是 Python 实现的副作用,而不是错误。

    您没有包含用于(取消)编组 protobuf 的代码。

    在您的示例中,logoff_event 是否包含 LogoffEvent 消息类型?

    你说不确定?对于客户端发送的相同消息,您是否在服务器上看到不同的 event_payload 消息类型?

    返回的内容:

    msg = Wrapper() # Your decoded message
    assert msg.event.WhichOneof("event_payload")
    # or
    assert msg.event.HasField("login_event")
    

    Python Generated Code: OneOf

    更新 210927

    我无法重现您观察到的行为;它按我的预期工作。

    客户:

    import client_pb2
    
    msg = client_pb2.Wrapper()
    
    msg.id=0
    msg.name="Test"
    msg.event.event_id=1
    msg.event.login_event.y="Hello Freddie"
    
    print(msg)
    
    f=open("message","wb")
    f.write(msg.SerializeToString())
    f.close()
    

    产量:

    id: 0
    name: "Test"
    event {
      event_id: 1
      login_event {
        y: "Hello Freddie"
      }
    }
    

    服务器:

    import server_pb2
    
    msg = server_pb2.Wrapper()
    
    f=open("message","rb")
    msg.ParseFromString(f.read())
    f.close
    
    assert msg.event.WhichOneof("event_payload")
    assert msg.event.HasField("login_event")
    
    print(msg)
    

    产量:

    id: 0
    name: "Test"
    event {
      event_id: 1
      login_event {
        y: "Hello Freddie"
      }
    }
    

    【讨论】:

    • 是的,logff_event 确实包含 LogoffEvent 消息类型,是的,这正是我所说的非确定性。不过,我可能对此不正确,我可能只是缺少一个映射/模式。此外,为了解组,我使用 FromString 方法,然后使用 json_format.MessageToJson 将 msg 转换为 json,我最终将其加载为 python 字典。
    • 我已经更新了我的答案。它按我的预期工作。
    猜你喜欢
    • 2018-11-20
    • 2011-03-20
    • 2013-02-21
    • 1970-01-01
    • 2019-04-07
    • 1970-01-01
    • 2011-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多