注:この質問の長さについてお詫び申し上げます。多くの情報を入力する必要がありました。それがあまりにも多くの人々が単にそれをすくい取って仮定をすることを引き起こさないことを願っています。全部お読みください。ありがとう。
ソケットを介して入ってくるデータのストリームがあります。このデータは行指向です。
.NET(BeginReadなど)のAPM(非同期プログラミング方式)を使用しています。非同期I/Oはバッファベースであるため、これによりストリームベースのI/Oを使用できなくなります。データを再パッケージ化してメモリストリームなどのストリームに送信することは可能ですが、そこにも問題があります。
問題は、私の入力ストリーム(私は制御できません)がストリームの長さに関する情報を私に提供しないことです。これは、次のような改行行のストリームです。
COMMAND\n
...Unpredictable number of lines of data...\n
END COMMAND\n
....repeat....
したがって、APMを使用すると、特定のデータセットの長さがわからないため、データのブロックがバッファの境界を越えて複数の読み取りが必要になる可能性がありますが、これらの複数の読み取りも複数のデータブロックにまたがります。
例:
Byte buffer[1024] = ".................blah\nThis is another l"
[another read]
"ine\n.............................More Lines..."
私が最初に考えたのは、StringBuilderを使用して、SBにバッファー行を追加することでした。これはある程度は機能しますが、データのブロックを抽出するのは難しいことがわかりました。StringReaderを使用して新しい行のデータを読み取ろうとしましたが、StringReaderが最後に追加されたブロックの最後に部分的な行を返し、その後にnullを返すため、完全な行を取得しているかどうかを知る方法がありませんでした。返されたものが完全に新しいデータ行であったかどうかを知る方法はありません。
例:
// Note: no newline at the end
StringBuilder sb = new StringBuilder("This is a line\nThis is incomp..");
StringReader sr = new StringReader(sb);
string s = sr.ReadLine(); // returns "This is a line"
s = sr.ReadLine(); // returns "This is incomp.."
さらに悪いことに、データに追加し続けると、バッファがどんどん大きくなり、これは一度に数週間または数か月実行される可能性があるため、適切なソリューションではありません。
私の次の考えは、データのブロックを読んでいるときにSBからデータのブロックを削除することでした。これには独自のReadLine関数を作成する必要がありましたが、読み取りと書き込み中にデータをロックするのに行き詰まりました。また、データのより大きなブロック(数百の読み取りとメガバイトのデータで構成される可能性があります)では、バッファー全体をスキャンして改行を探す必要があります。それは効率的ではなく、かなり醜いです。
非同期I/Oの便利さを備えたStreamReader/Writerのシンプルさを備えたものを探しています。
私の次の考えは、MemoryStreamを使用し、データのブロックをメモリストリームに書き込み、次にStreamReaderをストリームに接続してReadLineを使用することでしたが、バッファーでの最後の読み取りが完全な行であるかどうかを知ることに問題があります。さらに、ストリームから「古い」データを削除するのはさらに困難です。
また、同期読み取りでスレッドを使用することも考えました。これには、StreamReaderを使用すると、接続が切断された場合を除いて、ReadLine()から常にフルラインが返されるという利点があります。ただし、これには接続のキャンセルに関する問題があり、特定の種類のネットワークの問題により、ブロッキングソケットが長時間ハングする可能性があります。データ受信をブロックしているプログラムの存続期間中、スレッドを拘束したくないので、非同期IOを使用しています。
接続は長続きします。そして、データは時間の経過とともに流れ続けます。最初の接続中は大量のデータフローがあり、そのフローが完了すると、ソケットは開いたままになり、リアルタイムの更新を待機します。最初のフローがいつ「終了」したかは正確にはわかりません。これ以上データがすぐに送信されないことを知る唯一の方法だからです。これは、最初のデータの読み込みが完了するのを待ってから処理することができないことを意味します。処理が開始されると、「リアルタイム」で処理が滞ります。
それで、誰かがこの状況を過度に複雑にならない方法で処理するための良い方法を提案できますか?私はこれをできるだけシンプルでエレガントにしたいと思っていますが、すべてのエッジケースのために、ますます複雑なソリューションを考え続けています。私が欲しいのは、特定の基準(つまり、改行で終了する文字列)に一致するデータをポップすると同時に、より多くのデータを簡単に追加し続けることができる、ある種のFIFOだと思います。