7

これは、私の他の質問からの分岐のようなものです。よろしければお読みくださいが、必須ではありません。

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

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

4

4 に答える 4

15

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

簡単なアプローチは、各「メッセージ」に固定サイズのヘッダーを持たせ、プロトコルバージョンとペイロードサイズの両方、およびその他の固定データを含めることです。次に、メッセージの内容(ペイロード)。

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

ペイロードサイズを知ることで、メッセージの残りの部分に十分なバイト数を読み取り続けることができます(読み取りがそれ以下で完了する場合は、メッセージ全体が受信されるまで残りのバイトに対して別の読み取りを実行します)。

終了メッセージインジケータも機能しますが、同じオクテットシーケンスを含むメッセージを処理する方法を定義する必要があります...

于 2009-02-25T17:33:21.620 に答える
6

パーティーに遅刻してすみません。私は C# 実装の 1 つである protobuf-net の作成者です。ネットワークの使用については、「[De]SerializeWithLengthPrefix」メソッドを検討する必要があります。これにより、長さが自動的に処理されます。ソースに例があります。

古い投稿について詳しくは説明しませんが、詳しく知りたい場合は、コメントを追加してください。折り返しご連絡いたします。

于 2009-03-26T08:33:29.677 に答える
3

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

有用なアプローチは、最下位レベルのコードでソケットからバッファーを読み取って、完全なメッセージを組み立て、部分的なメッセージを記憶するフレーミング レイヤーにそれらを提示することです (ここでは (CCR を使用して) 非同期アプローチを提示しますが、回線プロトコル)。

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

于 2009-03-01T06:04:23.350 に答える
1

TCP/IP および UDP のパケットには、サイズに関する参照が含まれています。IP ヘッダーには、 IP ヘッダーデータの長さをバイト単位で指定する 16 ビット フィールドが含まれます。TCP ヘッダーには、TCP ヘッダーのサイズを 32 ビット ワードで指定する 4 ビット フィールドが含まれます。UDP ヘッダーには、 UDP ヘッダーデータの長さをバイト単位で指定する 16 ビット フィールドが含まれます。

つまりね。

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

私がソケットを使用してこれまで見てきたすべての典型的なパターンは、送信するデータの前にアプリケーション レベルのヘッダーを定義することです。少なくとも、このヘッダーには、続くデータのサイズが含まれている必要があります。これにより、サイズを推測することなく、各「メッセージ」全体を読むことができます。たとえば、同期パターン、CRC、バージョン、メッセージのタイプなど、好きなだけ凝ったものにすることができますが、本当に必要なのは「メッセージ」のサイズだけです。

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

編集: Google Protocol Buffers プロジェクトに気付いたばかりです。私が知る限り、これは WCF のバイナリ シリアライゼーション/デシリアライゼーション スキームです (単純化しすぎていると思います)。WCF を使用している場合、送信されるメッセージのサイズについて心配する必要はありません。これは、WCF 配管が舞台裏でこれを処理するためです。おそらく、プロトコルでメッセージの長さに関連するものを見つけられなかったのはそのためです。バッファのドキュメント。ただし、ソケットの場合は、サイズを知っておくと、上で説明したように非常に役立ちます。私の推測では、Protocol Buffers を使用してデータをシリアライズし、それを送信する前に思いついたアプリケーション ヘッダーを追加します。受信側では、ヘッダーを取り出してから、メッセージの残りを逆シリアル化します。

于 2009-03-01T05:32:43.567 に答える