我正在尝试通过 TCP 发送协议缓冲区消息,但在接收端我在尝试解析时收到“缺少必填字段”错误,即使显然所有字段都在那里。我在包含消息长度的消息之前发送了一个 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_ 是接收 TCP 数据的向量<uint8_t>。
我确认它的大小正确为 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 );
测试已成功填充正确的字段。