2010-11-18 7 views
5

(SFMLとRakNetを使用して)ネットワーク機能を備えたクロスプラットフォームゲームを作成しています。私はUbuntuサーバーでサーバーをコンパイルしてクライアントを取得しました私のMacで。すべての開発は私のMac上で行われていますので、当初はそのサーバーをテストしていましたが、うまくいきました。C++でクロスプラットフォーム構造体を作成して使用する

私はstructをネットワーク経由で送信してから、char *から(例えば)inet::PlayerAddedに戻して送信します。今これはうまく動作しています(大部分)が、私の質問です:これはいつも動作しますか?非常に壊れやすいアプローチのようです。構造体は、他のプラットフォーム(Windowsなど)でも同じレイアウトになっていますか?あなたは何をお勧めします?

#pragma pack(push, 1) 
struct Player 
{ 
    int dir[2]; 
    int left; 
    float depth; 
    float elevation; 
    float velocity[2]; 
    char character[50]; 
    char username[50]; 
}; 

// I have been added to the game and my ID is back 
struct PlayerAdded: Packet 
{ 
    id_type id; 
    Player player; 
}; 
#pragma pack(pop) 
+2

シリアルダウンボートには、何らかの理由がありますか? (スティーブのdownvoteは特に大変そうです) – KevinDTimm

+0

このような場所では意味がありません。私はそれについて心配しません。 –

+1

私はポイントについて気にしない、私はすべての答え(1つを除いて、すべての中で最も有用でない)がdownvoteを持っている理由を知りたい。特に(下落した)回答の1つが明らかに最高だったとき。 – KevinDTimm

答えて

5

他の多くの回答と同様に、回避できる場合は生のバイナリデータを送信することをお勧めします。 BoostのシリアルやGoogle Protobufのようなものは、あまりにも多くのオーバーヘッドをかけずにすばらしい仕事をします。

クロスプラットフォームのバイナリ構造を作成することはできますが、これは常に実行され、データを交換するための非常に有効な方法です。そのデータに "構造体"を重ねるだけで意味があります。しかし、レイアウトを非常に注意深くする必要があります。幸いにも、ほとんどのコンパイラはこれを行うための多くのオプションを提供しています。 "パック"はそのようなオプションの一つであり、多くの面倒を見る。

また、データサイズにも注意する必要があります。シンプルにstdint.hをインクルードし、uint32_tのような固定サイズのタイプを使用します。浮動小数点値に注意してください。そうしないと、すべてのアーキテクチャが同じ値を共有するわけではありません。また、エンディアンの場合、ほとんどのアーキテクチャーは同じものを使用しますが、そうでなければ、違うクライアントで単純にフリップすることができます。

+0

ほとんどの回答は本当に素晴らしかったが、これは私を最も助けてくれたものだと思う。私はそれを打つつもりだと思います。もし私がこの方法で障壁を打つと、私は何を使うべきかを知るでしょう。 – ErikPerik

9

正しいint表現は両者の間に逆転されるように、ビッグエンディアンのマシンにリトルエンディアンのマシンからそれを行うにしようとする(他のものの間で)場合、これは動作しません。

構造体の配置やパッキングがマシン間で変更されると、これも失敗する可能性があります。 64ビットマシンをいくつか持っていて、それに32ビットマシンがあればどうでしょうか?

Boost.SerializationまたはGoogle Protocol Buffersのような適切なポータブルシリアル化ライブラリを使用して、ハードウェアとは独立して正常にデコードできるワイヤプロトコル(伝送可能なデータ形式)を確保する必要があります。

プロトコルバッファに関する素晴らしい点は、プロトタイプストリームと互換性のあるZLIB互換ストリームを使用して透過的にデータを圧縮できることです。私は実際にこれを行った、それはうまく動作します。私は他のデコレータストリームを類似の方法で使用して、必要に応じて基本的なワイヤプロトコルを強化または最適化できると思います。

2

「他のプラットフォームでも同じようにレイアウトされています...」という答えは、一般的には「いいえ」です。これは、異なるCPUや異なるエンディアンのような問題に対処している場合でもそうです。

異なるオペレーティングシステム(同じハードウェアプラットフォームであっても)が異なるデータ表現を使用することがあります。これは通常「プラットフォームABI」と呼ばれ、例えば、 32ビット/ 64ビットWindows、32ビット/ 64ビットLinux、MacOSX。

「#pragma pack」は、配置の制限を超えてデータ型のサイズの違いがあるため、半分にすぎません。たとえば、64bit Windowsでは「long」、Linuxでは32bit、MacOSXでは64bitです。

問題は明らかに新しいものではなく、過去にすでに解決されています。リモートプロシージャコール標準(RPC)には、プラットフォームに依存しない方法でデータ構造を定義する方法と、これらの構造体を表す "バッファ"をデコードします。これは「XDR」(eXternal Data Representation)と呼ばれています。 RFC1832を参照してください。 プログラミングが進むにつれて、このホイールは何度も再発明されました。 XMLに変換しても、XDRで低レベルの作業をしても、google :: protobuf、boostまたはQt :: Variantを使用すると、選択肢がたくさんあります。純粋に実装側で

:simplicltyについては、単にどこでも「unsigned int型は、」32ビット境界で整列32ビットであることを前提としています。すべてのデータを32ビット値の配列としてエンコードすることができれば、対処しなければならない外部化の問題はエンディアンだけです。

関連する問題