在 protobuf 中处理可选消息的正确方法是啥?

Posted

技术标签:

【中文标题】在 protobuf 中处理可选消息的正确方法是啥?【英文标题】:What is the proper way to handle optional messages in protobuf?在 protobuf 中处理可选消息的正确方法是什么? 【发布时间】:2012-06-03 16:20:28 【问题描述】:

考虑以下实现:

person.proto:

    enum PhoneType 
  MOBILE = 0;
  HOME = 1;
  WORK = 2;


message PhoneNumber 
  required float number = 1;
  required PhoneType type = 2;


message Person 
  required string name = 1;
  optional PhoneNumber number = 2;

main.cpp:

#include <stdint.h>
#include <stdio.h>

#include "person.pb.h"

#include <iostream>

int main(int argc, char *argv[])

    static const uint32_t outputbuflen = 1024;
    uint8_t outputbuffer[outputbuflen];
    uint32_t writtenlenght = 0;

    // Encode a person and send it over any datalink.

    // SENDER
    Person p_sender;
    p_sender.set_name("FooBar");

    // Set the phonenumber.
    // Does not work because returns const ref.
    // p.number().set_number(0123123);

    // Is this correct?
    PhoneNumber * number = p_sender.mutable_number();
    number->set_number(0800123123.0);
    number->set_type(MOBILE);

    p_sender.SerializeToArray(outputbuffer, outputbuflen);
    writtenlenght = p_sender.ByteSize();

    std::cout << writtenlenght << "B written to output."<< std::endl;

    // Great, now send the stream somwhere
    // sendStream(...);

    // RECEIVER
    // Does not know how many bytes to expect, so we'll let protobuf handle that.
    // Simulate a reception loop.
    Person p_receiver;
    uint32_t bytesparsed;
    for(bytesparsed = 0; bytesparsed < writtenlenght; bytesparsed++)
        // Look at the data as if receiving it byte by byte.
        std::cout << "Trying to parse message " << bytesparsed << std::endl;
        if(p_receiver.ParseFromArray(outputbuffer, bytesparsed))
            std::cout << "Found message" << std::endl;;
            break;
        
    

    std::cout << "Needed " << bytesparsed << "B to read message, but has still " \
              << writtenlenght - bytesparsed << "B left in buffer" << std::endl;
    return 0;

使用:https://developers.google.com/protocol-buffers/ 在现实世界的情况下,接收者不会知道应该接收的字节数,但 protobuf 应该(据我所知)能够检查缓冲区中的完整消息。如果没有可选消息,这似乎工作正常。此刻它没有发生,我最终得到了一个没有电话号码的破碎的人。 :) 我做错了什么,这种情况应该如何处理?

【问题讨论】:

【参考方案1】:

Protocol Buffers 序列化格式不包括框架(即将序列化消息打包到流或分隔消息)。你需要自己做。

但是,有一些既定的做法。详情请查看这两个答案:

https://***.com/a/5586945/618259 https://***.com/a/2341658/618259

【讨论】:

看看我的 .proto 文件。它只有一条我要发送的消息,其中有一条可选消息。这不是您的链接中的两条不同的消息。 其实我觉得我碰到了这个:code.google.com/p/protobuf/issues/detail?id=377 不,事实并非如此。无论您是想流式传输多条消息还是只发送一条消息,阅读器必须知道输入消息的大小才能正确解码。如果您阅读编码规范,就会变得很明显:developers.google.com/protocol-buffers/docs/encoding 不应该 ParseFromArray 在我的示例中返回 false,因为消息不完整? ParseFromAray 不可能知道消息是否完整。您可以通过只提供必填字段来满足它。您为解析消息选择的方法不精确且效率非常低,请参阅我之前发布的链接和解释以了解如何正确执行此操作。您应该提供要解析的消息的确切大小。

以上是关于在 protobuf 中处理可选消息的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

protobuf-net 中日期时间的 .proto 消息是啥

python中的Protobuf文件版本控制

在 SwiftyJSON 中处理可选元素的最佳方法是啥?

处理鼠标拖动的正确方法是啥?

处理发布到 Nodejs 服务器的 JSON 消息数组的最佳方法是啥?

在Android中获取FCM消息令牌的正确方法是啥?