小さなマルチプレイヤー ゲーム用のプロトコルを実装しました。これはバイトに基づいていたので、受信したメッセージをデシリアライズするには、バイト ストリームを繰り返し処理し、ビットごとに解析する必要がありました。すべてのバイトを取得し、メッセージの種類を把握した後、未加工のバイトからプロトコル データ ユニットを構築するリバース コンストラクターにバイトを投入しました。
このプロセス全体は非常に醜く、実際には OO ではなく、判読できないif/elseコードがありました。reverseConstructor(byte[] bytes)
追加したすべてのプロトコル データ ユニット (pdu) を実装する必要がありました。ある種のスキーマが pdu ごとに定義されているアプローチ (たとえば、スキーマ = [1 バイトの int (id = x)、x バイトの ascii 文字列、4 バイトの double])、およびバイトの処理がそのスキーマで行われるアプローチは、次のようになります。よりエレガントに。
ここで、Googleのprotobufを使用するためのヒントを得ました (protobuf標準に準拠するにはプロトコルを変更する必要があるため、明らかにそれらは私のニーズに合わないようです)。
情報
プロトコルを変更できません。2 つの異なるシナリオがあります (同時に、または同じプログラム内でさえもサポートしたくありません)。
- プロトコル データ ユニットには、ヘッダーにエンコードされた長さフィールドがあります。
- プロトコル データ ユニットには長さフィールドはありませんが、メッセージがいつどこで終了するかをメッセージ タイプから導き出すことができます。
私は個人的に長さフィールドのファンです。しかし、他の誰かが設計したプロトコルに従わなければならない場合もあります。したがって、プロトコルは修正されています。それらはすべて、プロトコル ID、一意のメッセージ ID、および最初のシナリオでは長さフィールドを含むヘッダーを持っています。
質問
効率的で一般的な受信メソッドによって解析される 2 つの単純なプロトコル データ ユニットを使用した非常に小さな例を誰か教えてもらえますか? protobuf チュートリアルで見つけた唯一の例は、ユーザー a がメッセージ x を送信し、ユーザー b がメッセージ X を予期し、問題なく逆シリアル化できるタイプのものだけでした。
しかし、ユーザー b がメッセージ x、y、z に対して準備をしなければならない場合はどうなるでしょうか。コードをあまり重複させずに、インテリジェントな方法でこの状況を処理するにはどうすればよいでしょうか。
また、extern ライブラリを使用せずに、ここでより優れたコードを実現できるようにする設計原則へのヒントもいただければ幸いです。
編集
私はそのような sth が行く方法だと思います。コードの詳細については、こちらを参照してください。オブジェクトが見つかるまでバイトが動的に読み取られ、その後バッファの位置がリセットされます。
while (true) {
if (buffer.remaining() < frameLength) {
buffer.reset();
break;
}
if (frameLength > 0) {
Object resultObj = prototype.newBuilderForType().mergeFrom(buffer.array(), buffer.arrayOffset() + buffer.position(), frameLength).build();
client.fireMessageReceived(resultObj);
buffer.position(buffer.position() + frameLength);
buffer.mark();
}
if (buffer.remaining() > fieldSize) {
frameLength = getFrameLength(buffer);
} else {
break;
}
}
JavaDoc - mergeFrom
データをこのタイプのメッセージとして解析し、作成中のメッセージとマージします。これは、MessageLite.Builder.mergeFrom(CodedInputStream) の小さなラッパーです。 https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/Message.Builder#mergeFrom(byte[])
問題はこのタイプの部分メッセージですが、一般的なアプローチでこの問題に対処できるはずです。
サンプル
サンプルのプロトコル データ ユニットを次に示します。長さフィールドがあります。pdus に長さフィールドがない別のシナリオがあります。この PDU は可変サイズです。固定サイズの pdu もあります。
完全を期すために。ここでは、プロトコル データ ユニットでの文字列の表現を示します。