コンシューマDFAとソケットクライアントの間にバッファコンポーネントを追加する必要があります。
データがバッファから利用可能であるときはいつでもNetworkStream
、バッファコンポーネントはそれを読み取り、それをそれ自身のプライベートバッファに追加し、「利用可能なバイト」カウンタをインクリメントします。バッファコンポーネントは、少なくとも次の機能をユーザーに公開する必要があります。
- プロパティ-これは
BytesAvailable
カウンターの値を返します
PeekBytes(int count)
メソッド-これは、少なくともその量が使用可能な場合、バッファーの最初のバイトを返し、count
カウンターまたはバッファーを変更しません
- メソッド-上記と同じですが、
ReadBytes(int count)
カウンターをデクリメントしcount
、バッファーから読み取られたバイトを削除して、後続のPeekBytes
呼び出しがそれらを二度と読み取らないようにします。
count
任意に高いパラメータを処理できる必要はないことに注意してください。count
常に受信できる最長のメッセージを処理できれば十分です。
明らかに、バッファコンポーネントは、ある種の「ラップアラウンド」を可能にするある種のデータ構造を保持する必要があります。循環(リング)バッファの実装を調べるか、最長のメッセージの長さであるサイズの2つの固定バッファを使用して、いっぱいになったときに一方から他方に切り替えることができN
ますN
。NetworkStream
バッファがいっぱいになった場合にデータのプルを停止し、DFAがReadBytes
バッファスペースを解放するために呼び出した後にのみプルを続行するように注意する必要があります。
DFAがデータを読み取る必要があるときはいつでも、最初にバッファステージに蓄積されたデータの量を尋ね、次にそれに応じて続行します。次のようになります。
if BytesAvailable < 2
return; // no header to read, cannot do anything
// peek at the header -- do not remove it from the buffer!
header = PeekBytes(2);
// calculate the full message length based on the header
// if this is not possible from just the header, you might want to do this
// iteratively, or you might want to change the header so that it is possible
length = X;
if BytesAvailable < X
return; // no full message to read, cannot continue
header = ReadBytes(2); // to remove it from the buffer
message = ReadBytes(X); // remove the whole message as well
このようにして、DFAはメッセージ全体のみを処理します。