4

私はゲームサーバーを設計していますが、これまでにこのようなことをしたことはありません。私は、パケットのデータに関する適切な構造とはどのようなものだろうかと思っていました。問題がある場合はTCPを使用しています。これが例であり、私が今のところ使用を検討していたものは次のとおりです。

(括弧内の各値はバイト)

[Packet length][Action ID][Number of Parameters]
[Parameter 1 data length as int][Parameter 1 data type][Parameter 1 data (multi byte)]
[Parameter 2 data length as int][Parameter 2 data type][Parameter 2 data (multi byte)]
[Parameter n data length as int][Parameter n data type][Parameter n data (multi byte)]

私が言ったように、私は本当にこれまでにこのようなことをしたことがないので、私が上に持っているものは完全な雄牛かもしれません;それが私が尋ねている理由です;) また、必要なパケットの合計長を渡すことはありますか?

4

5 に答える 5

3

車輪の再発明を避けるために、任意のシリアル化プロトコルが通信データ (XML、JSON など) で機能します。基本的なプロトコル フレームワークとしてBEEPを検討することを検討してください。

BEEP は、80 年代初頭から経験豊富なアプリケーション プロトコル設計者が使用したトリックの「ベスト ヒット」アルバムのようなものとして、その FAQ ドキュメントにうまくまとめられています。'

于 2008-12-27T13:38:58.150 に答える
3

パケットの合計長を渡すことをお勧めします。さらに 2 バイトのコストがかかる場合がありますが、受信する前に、ソケットが完全なパケットを飲み込む準備ができるまで覗いて待つことができます。これにより、コードが簡単になります。

全体として、私は brazzy に同意します。言語提供のシリアル化メカニズムは、自作よりも好ましいです。

それ以外 (シリアライゼーションなしで C っぽい言語を使用していると思います) では、パケット ID をパケット データ構造の最初のデータとして配置します。構造体の最初のデータメンバーは常に位置0にあり、任意の構造体をそれにダウンキャストできるため、それ以外の場合は匿名データを識別できるため、これはある種の規則です。

コンパイラはパックされた構造体を生成する場合と生成しない場合がありますが、そのようにして、バッファーを割り当て、パケットを読み取り、最初のデータ メンバーに応じて構造体をキャストできます。運が悪く、パックされた構造体が生成されない場合は、(明らかに宛先ではない) メモリから構築される各構造体のシリアル化メソッドを必ず用意してください。

エンディアンは、特に C ライクな言語の要因です。パケットのエンディアンが常に同じであること、または署名などに基づいて異なるエンディアンを識別できることを明確にしてください。非常にクールな奇妙なこと: C# と .NET は、この投稿で説明されているようにアクセスすると、常にリトルエンディアン規則でデータを保持しているようです。そのようなアプリケーションを SUN 上の Mono に移植するときに、そのことがわかりました。クールですが、その設定がある場合は、とにかく C# のシリアル化手段を使用する必要があります。

それ以外は、セットアップは非常に問題ないようです。

于 2008-12-27T11:37:42.373 に答える
3

はるかに単純な基本的なラッパーであるタグ、長さ、値 (TLV) を検討することから始めます。基本的なパケットは次のようになります。

[Tag] [Length] [Value]

タグはパケット識別子 (アクション ID など) です。

長さはパケット長です。これは、完全なパケットがあるかどうかを判断するために必要になる場合があります。また、値の部分の長さを把握することもできます。

には実際のデータが含まれます。この形式は何でもかまいません。

上記の場合、値データにはさらに一連の TLV 構造 (パラメーターの型、長さ、値) が含まれています。データの長さとデータのウォークから処理できるため、実際にはパラメーターの数を送信する必要はありません。

他の人が言ったように、私はパケット ID (タグ) を最初に置きます。クロスプラットフォームの問題がない限り、アプリケーションのシリアル化されたオブジェクトを TLV でラップし、そのようにネットワーク経由で送信することを検討します。間違えた場合や後で変更したい場合は、いつでも別の構造の新しいタグを作成できます。

TLVの詳細については、ウィキペディアを参照してください。

于 2008-12-27T12:46:26.633 に答える
2

そんなに複雑なものを作る理由はありません。アクション ID が表示されているので、アクションの数は決まっていると思います。

アクションごとにデータ構造を定義し、それらの値をそれぞれ構造に入れます。ネットワーク経由で送信するには、構造体の各要素に sum(sizeof(struct.i)) バイトを割り当てるだけです。したがって、パケットは次のようになります。

[action ID][item 1 (sizeof(item 1 bytes)][item 1 (sizeof(item 2 bytes)]...[item n (sizeof(item n bytes)]

アイデアは、接続の両側の各変数のサイズとタイプが既にわかっているため、その情報を送信する必要がないということです。

文字列の場合は、null で終了する形式でそれらを投げ込むだけで、パケットの種類に基づいて文字列を探すことが「わかっている」場合は、読み取りを開始して null を探します。

--

別のオプションは、'\r\n' を使用して変数を表すことです。これにはいくらかのオーバーヘッドが必要であり、数値にはバイナリ値ではなくテキストを使用する必要があります。しかし、そうすれば、readline を使用して各変数を読み取ることができます。パケットは次のようになります

[action ID]
[item 1 (as text)]
...
[item n (as text)]

--

最後に、単純にオブジェクトをシリアル化してネットワークに渡すことも、作成するコードの量を最小限に抑えてこれを行うための良い方法です。時期尚早に最適化したくないことを忘れないでください。これには、ネットワーク トラフィックも含まれます。後でもう少しパフォーマンスを絞り出す必要があることが判明した場合は、戻ってより効率的なメカニズムを見つけ出すことができます。

Google のprotocol buffersを確認してください。これは、プラットフォームに依存しない方法でデータをシリアル化するための非常に高速な方法であり、バイナリ XML のようなものですが、ネストされた要素はありません。また、別のプラットフォームに依存しないエンコーディングであるJSONもあります。プロトコル バッファまたは JSON を使用すると、メッセージを具体的にエンコードする方法について心配する必要がなくなります。

于 2008-12-27T11:44:42.903 に答える
0

サーバーが異なる言語で書かれた複数のクライアントをサポートするようにしますか? そうでない場合は、おそらく構造を正確に指定する必要はありません。代わりに、エラーの可能性を減らすために、言語が提供するデータのシリアライズ機能を使用してください。

構造を移植可能にする必要がある場合、上記は問題ないように見えますが、その場合はエンディアンやテキストエンコーディングなども指定する必要があります。

于 2008-12-27T11:26:50.023 に答える