首页 > 解决方案 > 为什么我的 protobuf 反序列化给出了空的有效载荷?

问题描述

在带有 VS2017 的 Windows 上运行 protobuf 3.9.0,我试图在 C++ 中使用CodedOutputStream和反序列化我的 protobuf 模型CodedInputStream,但解码器总是给我一个空的结果。我使用长度前缀,可以从解码器端的流中读取大小。一个in-place encode/decode源码如下,其中Any使用了message

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, '\0');
    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.

我哪里错了?

标签: c++protocol-buffers

解决方案


您在编码时将任何类型的 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, '\0');

    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;
}

推荐阅读