Почему я все еще получаю данные даже после того, как NetworkStream.EndRead возвращает 0 байт?

Я использую NetworkStream.BeginRead/EndRead для асинхронного чтения из сокета.

Тем не менее, NetworkStream.EndRead() иногда возвращает 0 (т. е. из сокета было прочитано 0 байт), что, как я думал, указывает на то, что сокет был закрыт, но это неверно, потому что, если я продолжаю вызывать BeginRead(), в конечном итоге я получаю больше данных.

Разве это не правильный цикл для непрерывного чтения данных из сокета/NetworkStream?

void BeginContinousRead()
{
  // Start the continous async read
  mStream.BeginRead(mDataBuffer, 0, mDataBuffer.Length, new AsyncCallback(ProcessNetworkStreamRead), null);
}

private void ProcessNetworkStreamRead(IAsyncResult result)
{
  // This will sometimes be zero?!
  int bytesRead = mStream.EndRead(result);

  // Continue reading more data and call this callback method again over and over, etc.
  mStream.BeginRead(mDataBuffer, 0, mDataBuffer.Length, new AsyncCallback(ProcessNetworkStreamRead), null);
}

Согласно MSDN, я должен использовать свойство NetworkStream.DataAvailable, чтобы определить, доступны ли дополнительные данные в сокете, но это будет FALSE, даже если дополнительные данные могут появиться позже.

Например, согласно MSDN, это должен быть мой обратный вызов:

private void ProcessNetworkStreamRead(IAsyncResult result)
{
  // This will sometimes be zero?!
  int bytesRead = mStream.EndRead(result);

  while (mStream.DataAvailable)
    mStream.BeginRead(mDataBuffer, 0, mDataBuffer.Length, new AsyncCallback(ProcessNetworkStreamRead), null);
}

... но это не работает должным образом, потому что DataAvailable становится FALSE, а затем мое непрерывное чтение останавливается и никогда больше не читает данные.

Каков правильный асинхронный подход для продолжения чтения данных до тех пор, пока другой конец не закроет сокет или я не решу закрыть сокет?


person SofaKng    schedule 21.03.2012    source источник


Ответы (1)


Вместо того, чтобы проверять свойство bytesRead или DataAvailable, чтобы проверить, закрыт ли сокет, оберните вызов BeginRead и перехватите исключение IOException. Затем это должно сказать вам, закрыт ли сокет.

person hometoast    schedule 21.03.2012
comment
Спасибо. Какой тогда будет правильный цикл? Продолжайте вызывать BeginRead() и позволять EndRead() возвращать 0 байт снова и снова? - person SofaKng; 21.03.2012
comment
Я только что проверил это, подключившись по телнету к моему прослушивающему сокету, и по какой-то причине исключение НИКОГДА не выдается даже после того, как я отключил свой клиент telnet... - person SofaKng; 21.03.2012