13
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

NetworkStream.DataAvailable についての勘違い

Last updated at Posted at 2015-03-17

#はじめに

まとめを言ってしまいます。

  • 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」でググると「データの終端の判断材料に使うべきじゃない」
というような記事がちょくちょく見当たるので、よくある誤りなのかな。

#参考

13
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?