10

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

これは、結果のバッファーの16進印刷であり、最初の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データが受信されるvector<uint8_t>です。

13バイトで正しいサイズになっていることを確認しました。これは、16進ダンプです。これは、シリアル化後にバッファクライアント側をダンプしたときに得られるものと同じです。

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

テストには正しいフィールドが正常に入力されています。

4

2 に答える 2

6

問題は、ベクターデータへのポインターではなく、ベクターへのポインターを渡していることです。

それ以外の
request_.ParseFromArray( &data_buffer_, data_buffer_.size() );

試す
request_.ParseFromArray( &data_buffer_[0], data_buffer_.size() );

于 2012-12-18T13:38:09.003 に答える
1

必須フィールドが欠落しているが不要であり、プロトファイルでそのフィールドをオプションに変更できない場合の別の解決策は、ParseFromArrayの代わりにParsePartialFromArrayを使用できます。

protobufのドキュメントを参照してください:https ://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message_lite

于 2018-10-30T10:25:33.503 に答える