Google协议缓冲区 - 即使显然存在所有字段,也会丢失必填字段

时间:2012-12-18 12:58:44

标签: c++ boost-asio protocol-buffers

我正在尝试通过TCP发送协议缓冲区消息,但是在接收端我尝试解析时遇到“Missing required fields”错误,即使显然所有字段都在那里。我在包含消息长度的消息之前发送一个4字节的标题。

这是消息定义:

message ReplayRequest {
  required string channel = 1;
  required uint32 start = 2;
  required uint32 end = 3;
}

在客户端,我正在对标头进行编码并将消息序列化为矢量。

ReplayRequest req;
req.set_channel( "channel" )
req.set_start( 1 );
req.set_end( 5 );
int byte_size = req.ByteSize();
std::vector<uint8_t> write_buffer( HEADER_SIZE + byte_size );
encode_header( ... );
req.SerializeToArray( &write_buffer[HEADER_SIZE], byte_size );

这是生成的缓冲区的十六进制打印,其中前4个字节是编码的消息长度(13个字节)。

00 00 00 0d 0a 07 63 68 61 6e 6e 65 6c 10 01 18 05

在服务器端,我收到标头,对其进行解码,然后接收N个字节,其中N是标头中报告的消息大小。删除标头的服务器中的缓冲区为:

0a 07 63 68 61 6e 6e 65 6c 10 01 18 05

这与编码的客户端减去标题完全相同,但是当我尝试ParseFromArray这个缓冲区时,我收到一个错误:

libprotobuf ERROR c:\umdf_runtime\protobuf-2.4.1\src\google\protobuf\message_lit
e.cc:123] Can't parse message of type "ReplayRequest" because it is missing 
required fields: channel, start, end

调试时我注意到解码失败的地方是protobuf生成代码的这一部分:

bool ReplayRequest::IsInitialized() const {
  if ((_has_bits_[0] & 0x00000007) != 0x00000007) return false;

  return true;
}
出于某种原因,

has_bits_在服务器端被读为零,但我无法弄清楚原因。

有什么想法吗?

如果重要的话,我正在使用boost :: asio作为网络部分。

更新

根据要求,我发布了调用parseFromArray的代码。

request_.ParseFromArray( &data_buffer_, data_buffer_.size() );

request_是一个ReplayRequest成员变量,直到此调用没有任何操作。

data_buffer_是向量&lt; uint8_t&gt;接收TCP数据的地方。

我确认它的大小正确为13个字节,这是它的十六进制转储,这与我在序列化后转储缓冲区客户端时得到的相同。

0a 07 63 68 61 6e 6e 65 6c 10 01 18 05

更新2

我能够在客户端将缓冲区解析为另一个ReplayRequest实例,即:

...snip...
req.SerializeToArray( &write_buffer[HEADER_SIZE], byte_size );
ReplayRequest test;
test.ParseFromArray( &write_buffer[HEADER_SIZE], byte_size );

使用正确的字段成功填充测试。

2 个答案:

答案 0 :(得分:6)

问题是你传入了一个指向矢量的指针,而不是指向矢量数据的指针。

而不是
request_.ParseFromArray( &data_buffer_, data_buffer_.size() );

尝试
request_.ParseFromArray( &data_buffer_[0], data_buffer_.size() );

答案 1 :(得分:1)

另一种解决方案,如果缺少必填字段但您却不需要,并且无法在原型文件中将该字段更改为可选字段,则可以使用ParsePartialFromArray代替ParseFromArray。

请参阅protobuf文档:https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message_lite