2009-02-25 3 views
6

これは私のother questionの枝のようなものです。あなたが好きならそれを読むが、それは必要ではない。プロトコルバッファメッセージが完全に受信されたことを検出する方法はありますか?

基本的には、大きなメッセージに対してC#のBeginReceive()を効果的に使用するには、(a)パケットの長さを最初に読み取り、次にそのバイト数を正確に読み取るか、(b) -packetデリミタ。私の質問は、これらのいずれかがプロトコルバッファに存在するかどうかです。私はまだそれらを使用していませんが、長さのヘッダーや区切り文字があるようには見えません。

どうすればよいですか?メッセージを作成して、長さヘッダ/ EOP区切り文字をプレフィックス/サフィックスに付ける必要がありますか?

答えて

14

プロトコルにサイズまたは終了マーカーを含める必要があります。無作為に別々のパケットに分割されたオクテットの無期限ストリームをサポートする以外に、ストリームベースのソケット(TCP/IP)には何も組み込まれていません(パケットは転送中にも流出する可能性があります)。

単純なアプローチは、各「メッセージ」が固定サイズのヘッダーを持ち、プロトコルバージョンとペイロードサイズとその他の固定データの両方を含むことです。メッセージ内容(ペイロード)。

オプションで、メッセージフッタ(固定サイズ)にチェックサムまたは暗号署名(信頼性/セキュリティ要件に応じて)を追加することもできます。

ペイロードサイズを知っていると、メッセージの残りの部分で十分なバイト数を読みとることができます(読み込みが少なくて済むと、メッセージ全体が受信されるまで残りのバイトが読み込まれます) )。

終了メッセージインジケータも動作しますが、あなたがその同じオクテット配列を含む、あなたのメッセージを処理する方法を定義する必要があります...

1

TCP/IPだけでなく、UDPたが、パケットはそのサイズにいくつかの参照を含めます。 IP headerには、IPヘッダーの長さを指定する16ビットのフィールドバイトが含まれています。 TCP headerには、32ビットワードのTCPヘッダーのサイズを指定する4ビットのフィールドが含まれています。 UDP headerには、UDPヘッダーの長さを指定する16ビットのフィールドバイトが含まれます。

ここが問題です。

C#でSystem.Net.Sockets名前空間を使用している場合でも、Win32でネイティブWinsockを使用している場合でも、Windowsの標準的な常用ソケットを使用すると、IP/TCP/UDPヘッダーが表示されません。これらのヘッダーは取り除かれ、ソケットを読み取ったときに得られるものは実際のペイロード、つまり送信されたデータです。

私が今までに見たことがありソケットを使って行ったすべての典型的なパターンは、送信するデータに先行するアプリケーションレベルのヘッダーを定義することです。少なくともこのヘッダーには、データのサイズを含める必要があります。これにより、それぞれの "メッセージ"をそのサイズについて推測することなく、全体として読むことができます。同期パターン、CRC、バージョン、メッセージの種類など、あなたが望むように思い通りになることができますが、「メッセージ」のサイズはすべてです。が必要です。

そして、それは価値があるので、パケットの終わりの区切り記号の代わりにヘッダーを使用することをお勧めします。 EOPデリミタには大きな欠点があるのか​​どうかはわかりませんが、ヘッダーは私が見たほとんどのIPプロトコルで使用されているアプローチです。また、私のメッセージが完全であることを示すためにストリームにいくつかのパターンが現れるのを待つのではなく、最初からメッセージを処理する方が直感的です。

編集:私はちょうどGoogleプロトコルバッファープロジェクトを認識しています。私が知ることから、それはWCFのためのバイナリのシリアライズ/デシリアライゼーションスキームです(私はそれが大過剰の単純化であると確信しています)。 WCFを使用している場合は、WCF配管が裏でこれを処理するため、送信されるメッセージのサイズについて心配する必要はありません。これはおそらくプロトコルでメッセージの長さに関連するものバッファのドキュメント。しかし、ソケットの場合は、サイズを知ることは、上記のように大いに役立ちます。私の推測では、プロトコルバッファーを使用してデータをシリアル化し、それを送信する前に思い付くアプリケーションヘッダーをタックします。受信側では、ヘッダーを取り除き、残りのメッセージを逆シリアル化します。

+0

protobuf-netを意味するなら、それはWCFだけではありません。プロジェクトにソケットの例があります。 –

3

私は、PBがバイナリプロトコルであるという主な理由から、有効なメッセージシーケンスではないフッターを考え出すのは問題であるという点で、ヘッダがプロトコルバッファのフッターより優れていることに同意します。メッセージコンテンツが定義された範囲(通常0x20〜0x7F ASCII)にあるため、多くのフッターベースのプロトコル(通常はEOLプロトコル)が機能します。

あなたの最下位レベルのコードをソケットのバッファから読み取って、完全なメッセージを組み立て、部分的なメッセージを組み立てるフレーミングレイヤーまで提示するのが便利な方法です(これはCCRを使用して非同期的なアプローチです) here、ラインプロトコルの場合もあります)。

一貫性を保つために、メッセージを3つのフィールド(長さとして固定長、型として列挙型、実際のデータを含むバイト列)を持つPBメッセージとして定義することができます。これにより、ネットワークプロトコル全体が透過的になります。

6

パーティーで遅く到着したことに対するお詫び。私はprotobuf-netの著者であり、C#実装の1つです。ネットワークの使用法については、 "[De] SerializeWithLengthPrefix"メソッドを考慮する必要があります。そうすれば、自動的に長さが処理されます。ソースには例があります。

私は古い投稿については詳細には触れませんが、もっと知りたい場合はコメントを追加してください。

関連する問題