为什么我的 protobuf 反序列化给出空负载?

Why is my protobuf deserialization giving empty payload?

运行 protobuf 3.9.0 on Windows with VS2017,我正在尝试在 C++ 中使用 CodedOutputStreamCodedInputStream 序列化和反序列化我的 protobuf 模型,但是解码器总是给我一个空的结果。我使用长度前缀,可以从解码器端的流中读取大小。一个就地encode/decode源码如下,其中使用了Any消息

import "google/protobuf/any.proto";

message Pouch {
    google.protobuf.Any msg = 1;
}
bool EncodeDecode(google::protobuf::Message* pMeta, std::string& out_packet) {  
    //
    // Encoding
    //
    // CAUTION:
    // - Must dynamic allocate to avoid protobuf bug <SharedDtor crash #435>.
    std::shared_ptr<Pouch> pPayload = std::make_shared<Pouch>();
    google::protobuf::Any env;
    env.PackFrom(*pMeta);
    pPayload->set_allocated_msg(&env);  
    // Prefix with size
    const int nTipBytes = 4;
    int nBytesMsg = (int)pMeta->ByteSizeLong();
    int nBytesPacket = nBytesMsg + nTipBytes;
    out_packet.assign(nBytesPacket, '[=11=]');
    google::protobuf::io::ArrayOutputStream aos((void*)out_packet.c_str(), nBytesPacket);
    google::protobuf::io::CodedOutputStream cos(&aos);
    cos.WriteVarint32(nBytesMsg);   
    bool res = pMeta->SerializeToCodedStream(&cos);
    printf("payload has message: %d\n", pPayload->has_msg());
    //
    // Decoding
    //
    Pouch out_pouch;
    google::protobuf::io::ArrayInputStream ais(out_packet.c_str(), nBytesPacket);
    google::protobuf::io::CodedInputStream cis(&ais);
    google::protobuf::uint32 nPayloadBytes;
    cis.ReadVarint32(&nPayloadBytes);   
    google::protobuf::io::CodedInputStream::Limit msgLimit = cis.PushLimit(nPayloadBytes);
    res = out_pouch.ParseFromCodedStream(&cis);
    cis.PopLimit(msgLimit);

    printf("decoded payload has message: %d\n", out_pouch.has_msg());

    pPayload->release_msg();
    return res;
}

以上代码打印出一个空类型URL

payload has message: 1
decoded payload has message: 0

但是大小前缀 nPayloadBytes 给出了正确的数字。 编码和解码的结果都是true.

我哪里错了?

您在编码时将任何类型的 pMeta 包写入 CodedOutputStream cos,并在解码时期待消息 Pouch。 我认为您打算对 pPayload 消息而不是 pMeta 进行编码,它已经在其 msg 字段中包含 pMeta 消息。 用于测试的完整代码:

#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/util/delimited_message_util.h>
#include "teste.pb.h"

#include <string>

bool EncodeDecode(google::protobuf::Message* pMeta, std::string& out_packet) {  
    //
    // Encoding
    //
    // CAUTION:
    // - Must dynamic allocate to avoid protobuf bug <SharedDtor crash #435>.
    std::shared_ptr<Pouch> pPayload = std::make_shared<Pouch>();
    google::protobuf::Any env;
    env.PackFrom(*pMeta, "bob.bob.bob");
    pPayload->set_allocated_msg(&env);  
    // Prefix with size
    const int nTipBytes = 4;
    int nBytesMsg = (int)pPayload->ByteSizeLong();
    int nBytesPacket = nBytesMsg + nTipBytes;
    out_packet.assign(nBytesPacket, '[=10=]');

    google::protobuf::io::ArrayOutputStream aos((void*)out_packet.c_str(), nBytesPacket);
    google::protobuf::io::CodedOutputStream cos(&aos);
    cos.WriteVarint32(nBytesMsg);   
    bool res = pPayload->SerializeToCodedStream(&cos);
    printf("payload has message: %d\n", pPayload->has_msg());
    //
    // Decoding
    //
    Pouch out_pouch;
    google::protobuf::io::ArrayInputStream ais(out_packet.c_str(), nBytesPacket);
    google::protobuf::io::CodedInputStream cis(&ais);
    google::protobuf::uint32 nPayloadBytes;
    cis.ReadVarint32(&nPayloadBytes);   
    google::protobuf::io::CodedInputStream::Limit msgLimit = cis.PushLimit(nPayloadBytes);
    res = out_pouch.ParseFromCodedStream(&cis);
    cis.PopLimit(msgLimit);

    printf("decoded payload has message: %d\n", out_pouch.has_msg());
    if (out_pouch.has_msg()){
        Sample s;
        out_pouch.msg().UnpackTo(&s);
        printf("value: %d\n", s.number());
    }

    pPayload->release_msg();
    return res;
}

int main(){
    Sample *mymsg = new Sample();
    mymsg->set_number(5123);
    std::string bigstring;
    EncodeDecode(mymsg, bigstring);
}

和.proto:

syntax = "proto3";
import "google/protobuf/any.proto";

message Pouch {
    google.protobuf.Any msg = 1;
}

message Sample {
    int32 number = 1;
}