ここで Java 側では、ストリームをデシリアライズして、ストリームに 3 つのフィールドがあり、それぞれname
, type
, とvalue
事前にスキーマを知っておく必要があります。まず、protobufは名前を送信しません。識別子として使用するのは、各フィールドの数値キー ( 1
、2
および例では ) だけです。3
次に、型を明示的に指定しません。protobuf には非常に少数のワイヤ タイプしかありません (varint、32 ビット、64 ビット、長さプレフィックス、グループ)。実際のデータ型はそれらにマッピングされますが、スキーマなしでデータを明確にデコードすることはできません
- varint は「何らかの形式の整数」ですが、符号付き、符号なし、または「ジグザグ」(小さな大きさの負の数を安価にエンコードできる) にすることができ、任意の幅のデータ (64 ビット、32 ビット、等)
- 32 ビットは整数の場合もありますが、符号付きまたは符号なしの場合もあります。または、32 ビットの浮動小数点数の場合もあります。
- 64 ビットは整数の場合もありますが、符号付きまたは符号なしの場合もあります。または、64 ビットの浮動小数点数の場合もあります。
- length-prefix は、UTF-8 文字列、シーケンスまたは生のバイト (特に意味はありません)、
repeated
何らかのプリミティブ型 (整数、浮動小数点など) の値の「パックされた」セット、または構造化されたサブprotobuf 形式のメッセージ
- グループ - やったー!これは常に明白です!これが意味することは 1 つだけです。しかし、その1つはGoogleによって大部分が廃止されています:(
基本的に、スキーマが必要です。エンコードされたデータには、必要なものが含まれていません。不必要なスペースを避けるためにこれを行います - プロトコルがエンコーダとデコーダの両方がメッセージがどのように見えるかを知っていると想定している場合、送信する必要がある情報ははるかに少なくなります。
ただし、含まれている情報は、想定されていないフィールドがある場合でも、メッセージを安全に往復するのに十分であることに注意してください。再エンコードして渡す/戻すだけでよい場合は、名前やタイプを知る必要はありません。
できることは、パーサー API を使用してデータをスキャンし、3 つのフィールドがあることを明らかにすることです。フィールド 1 は varint、フィールド 2 は長さのプレフィックス、フィールド 3 は長さのプレフィックスです。それを超えて、データについて知識に基づいた推測を行うことができます (たとえば、UTF-8 デコードがほぼテキストのように見える何かを生成するかどうかを確認し、元のバイトを返す UTF-8 エンコーディングを検証できます。 、文字列である可能性があります)