クライアントサーバーネットワーク用の効率的なデータパッケージ


8

言語:C ++

私の質問は次のとおりです。データをパックしてクライアントからサーバーに、またはその逆に送信するための最良または少なくとも良い方法を知りたいのです。1つのパケットを構成するいくつかのデータがあります。パケットには「id」があり、それが何のためにあるかを定義します。次に、データは、パケットが対応する「アクション」に対して事前に決定された順序になります。

パフォーマンスに依存しないシステムでは、スペースで区切られた文字列を送信します。これは、「アクション」のデータと最初の「ワード」のパケット識別子であり、一致がある場合にステートメントがチェックする場合はチェーンします。 。

今、より重要なシステムのために、私がこれまでに考えたのは次のようなものでした:

パケットIDとデータで文字列を作成し、送信します。次に、アンパックするために、文字列の最初の整数を抽出し、パケットハンドラーの配列と、それらが処理するパケットIDに対応するインデックスを使用して、packetHandlers [packetID] .Process(packetData)のようにします。

あなたはそれについてどう思いますか、何か提案はありますか?大感謝です!

回答:


10

最初に、リソースを浪費して開発する前に、ファンシーで効率的なプロトコルが実際に必要かどうかを確認します。派手なプロトコルのため、ゲームのデバッグ/変更はより困難で時間がかかることを忘れないでください。ネットワーク通信を抽象化して、将来必要になった場合に実際の実装をより効率的な実装に簡単に交換できるようにします。パフォーマンスの問題が発生するまで、可能な限り単純なプロトコルを使用してください。プロトコルを後で設計するもう1つの利点は、転送される実際のデータと転送されると予測されるデータに対して、プロトコルを最適化できることです。

凝ったプロトコルが必要であることを確認した後、他の人が開発にかなりの時間を費やしたプロトコルを見てください。いくつかの例:

  • (更新) Protocol Buffers(v2 の最初の開発者は、Cap'n Protoと呼ばれる新しいプロトコルを開発しました。彼は自分の設計上の決定を説明し、最近リリースされた他の同様のライブラリと比較します:Cap'n Proto、FlatBuffers、SBEます。
  • Googleの主なボトルネックはコンピュータ間のネットワーク通信であるため、プロトコルバッファを開発する際に効率性を考慮した可能性があります。優雅にハンドル前方/後方互換性(あなたがあなたのデータ構造を変更することを決定しました)。すべての主要なGoogle製品(Gmail、検索など)で使用されます
  • Apache ThriftはFacebookで使用されている同様のプロトコルです。
  • RakNetは、ゲーム開発用に特別に設計されたオープンソースのネットワークライブラリです。
  • ZoidComは、ゲーム開発向けの別のネットワーキングライブラリです。オープンソースではありませんが、デザインのヒントについては引き続き調査できます。

プログラム最適化の最初のルール:実行しないでください。
プログラム最適化の2番目のルール(専門家のみ!):まだ実行しないでください。

[ マイケル・A・ジャクソン ]

つまり、主要な最適化パラメーターは次のようになります。寿命(プログラム実装ごとの寿命)。[ 独立したゲームをプログラムする方法。スライド21. Jonathan Blow。]


1
いい男だ!完全な答えをありがとう、それは確かに助けになりました、そしてあなたの忠告に完全に従って、私はこれを抽象化し、今のところそれを十分に単純にします:)
Grimshaw

Googleのプロトコルバッファの使用例が標準的な意味での効率ではなかったことは確かですが、考えられるすべてのプラットフォームと将来のデータバージョンとの互換性を最大化することです(これは別の観点からの効率です)。私はここで、他のメモを読んでいきます。主題を再確認するのに非常に便利なコレクションです。
Patrick Hughes

RakNetはオープンソースではありません。
Gerstmann

@Gerstmann:Raknetはオープンソースです(もう一度):github.com/OculusVR/RakNet
Leftium '7/7 '20

0

なぜ2つの異なるエンコーディングスキームを使用するのですか?すべてのシステムで2番目のものを使用してください。単純にしてください。
デルタ圧縮の使用を検討してください。つまり、1つの完全な値を送信し、その後に変更されたものだけを送信します。数回ゲームを繰り返した後、完全な値を再度送信します。
あなたが考えることができるもう一つのencodigはBase 128 Varintです。Google Protobufはそれを使用します。開発者ガイドの「エンコーディング」ページを見てください:プロトコルバッファエンコーディングは数バイトを節約できます。


私が話した最初のシステムは、別のプロジェクトからの単なる例でした:)私は確かにデルタ圧縮のアイデアを楽しんでいました。
グリムショウ2011

0

送信するデータの例は何でしょうか?過度に凝ったことをする理由は見当たらない。データが受信側のバッファーに完全に読み込まれたら、intその値に基づいて最初のデータを検査し、残りのデータを処理する方法を理解します。

4つのデータ部分を持っているパケットはそうidval1val2、とval2次のようになります。

// I'm using words (one byte) so my sample data is short
00000001 00101000 00010110 00010100 

最初のバイト(常にそこにあることがわかっています)を読み取るときに、次のデータセットの処理方法を決定します。最初の単語(id)が00000001わかっている場合は、さらに3つのdwordが続き、それがパケットの終わりです。例を続行するには、IDを持っているかもしれません= 00000010とあなたの仕様は、id値2のために、あなたが処理することを示していますfloatfloatfloatワールド空間におけるプレイヤーの位置を指定するかもしれないため、に。

独自のバイナリファイルシステムを記述すると考えてください。ヘッダー値があり、残りのデータ、データの場所(位置)、データの種類を記述します。


わかった、私が残した唯一の問題は、これらのintとfloatをすべて標準の文字列に十分にパックすることなのか、それとも軽量のデータ型を使うべきなのか?
グリムショウ

他の人が言ったように、文字列から始めて、何が起こるかを見てください。おそらく、コードの他の場所にボトルネックがあるでしょう。
ネイト
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.