プロトコルバッファメッセージが完全に受信されたときに検出する方法は?

StackOverflow https://stackoverflow.com/questions/586819

質問

これは私の枝の一種です その他の質問. 。必要に応じて読んでください。しかし、それは必要ありません。

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

そうでない場合、私は何をすべきですか?メッセージを作成してから、長さヘッダー/EOPデリミッターでプレフィックス/接尾辞を作成する必要がありますか?

役に立ちましたか?

解決

プロトコルにサイズまたはエンドマーカーを含める必要があります。ストリームベースのソケット(TCP/IP)に組み込まれているものはありません(TCP/IP)は、オクテットの無期限のストリームを任意に別々のパケットに分割することをサポートする以外にはありません(およびパケットも輸送中にこぼすことができます)。

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

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

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

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

他のヒント

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

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

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

有用なアプローチは、最低レベルのコードをソケットからバッファを読み取り、完全なメッセージを組み立てて部分的なメッセージを覚えているフレーミングレイヤーに表示することです(これに対する非同期アプローチを提示します(CCRを使用) ここ, 、ラインプロトコルではありますが)。

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

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

つまりね。

system.net.socketsの名前空間をC#で使用しているか、win32でネイティブWinsockのものを使用しているかどうかにかかわらず、Windowsで標準のMill run-of-the-Millソケットを使用すると、IP/TCP/UDPヘッダーが表示されません。これらのヘッダーは、ソケットを読んだときに得られるものが実際のペイロード、つまり送信されたデータになるように剥がれています。

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

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

編集:Google Protocol Buffers Projectに気付いただけです。私が言うことができることから、それはWCFのバイナリシリアル化/シリアル化スキームです(それは重大な過度の単純化だと確信しています)。 WCFを使用している場合、WCF配管が舞台裏でこれを処理するため、送信されるメッセージのサイズを心配する必要はありません。バッファドキュメント。ただし、ソケットの場合、サイズを知ることは、上記のように非常に役立ちます。私の推測では、プロトコルバッファーを使用してデータをシリアル化し、送信する前に思いついたアプリケーションヘッダーをタックします。受信側では、ヘッダーを脱いで、メッセージの残りの部分を除去します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top