#はじめに
まとめを言ってしまいます。
- DataAvailableは受信データの終端を判断するために使っても大丈夫だと思っていた。
- しかし本来DataAvailableは「読み取り対象のデータがあるかどうか」を判断するためのもの。
- DataAvailableの「false = 読み取りデータなし」は「データの終端」を意味するものではない。
- DataAvailableは受信データが残っていても false を返すことがある。(N/W遅延等?)
- なので「受信データの終端」を判断するにはDataAvailableではなくRead()を使うようにする。
#気付いた経緯
ソケットサーバーがクライアントからデータ受信する際、
クライアントからのデータが全て渡されたかどうかを判断するロジックで、
以下のように NetworkStream.DataAvailable を使っていました。
do {
memoryStream.Write(readBuffer, 0, readBuffer.Length)
}
while (netStream.DataAvailable);
しかしある環境下では、
まだデータが残っているにもかかわらず netStream.DataAvailable が false を返してきました。
そのため、正常なデータを受信できずに後の処理に影響が出てしまっていました。
#調べてわかったこと
NetworkStream.DataAvailable は「NetworkStream に読み取り対象のデータがあるかどうかを示す」ということ。
つまり「false = 読み取り対象のデータなし」は「受信データの終端」を意味するわけではないとのことでした。
なので例えば、ネットワーク状況の影響等でクライアントからのデータ到達が遅延した場合等、
まだデータが残っていても DataAvailable が false となることがあるようです。
要はデータの終端まで受信したかを判断するロジックに、
DataAvailableプロパティは使わないほうがいいということを知りました。
#じゃあどうするか
じゃあどうやって受信データの終端を判断するかというと、普通にRead()を使うほうが無難とのことです。
int numBytesRead;
do {
memoryStream.Write(readBuffer, 0, readBuffer.Length)
}
while ((numBytesRead = netStream.Read(readBuffer, 0, readBuffer.Length)) > 0);
MSDNの公式ドキュメントのコードを見てコーディングしていたらこの罠にかかってしまいました。
「NetworkStream.DataAvailable」でググると「データの終端の判断材料に使うべきじゃない」
というような記事がちょくちょく見当たるので、よくある誤りなのかな。
#参考