In Albahari’s book C # 6.0 in a Nutshell, the following is written:

In fact, the StreamReader class StreamReader absolutely forbidden to use with NetworkStream , even if you plan to call only the ReadLine method. The reason is that the StreamReader class has a read ahead buffer, which can lead to reading more bytes than is currently available, and endless blocking (or until a socket timeout occurs). Other streams, such as FileStream , do not suffer from such incompatibility with the StreamReader class, because they support a certain terminating attribute, when reached, the Read method ends immediately, returning the value 0 .

What error, for example, in this class?

 public class AsyncSocket : IDisposable { Socket socket; StreamReader sr; public AsyncSocket() { socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sr = new StreamReader(new NetworkStream(socket)); } // ... остальные члены убраны public async Task<string> ReadLineAsync() { return await sr.ReadLineAsync(); } public void Dispose() { if (sr != null) sr.Close(); if (socket != null) socket.Dispose(); } } 

Let's say the string "123 \ r \ nqwe" came. StreamReader counts all of it into its internal buffer when calling ReadLineAsync() will return "123". Data from the internal buffer is not deleted the same? The second call to ReadLineAsync() will end when the end of the line arrives and the result is "qwe". Albahari writes about infinite blocking, so the normal Read method can lead to it if no data is sent to the socket.

Explain why you cannot use the StreamReader class with NetworkStream ?

    1 answer 1

    The "read ahead buffer" means that the StreamReader will attempt to read a kilobyte ( bufferSize ) of data from the stream immediately. "In reserve". This improves performance when reading from a disk, but can lead to unpredictable consequences when reading.

    The peculiarity of NetworkStream.Read is that it can be blocked while reading (in case the socket is still open, but there is no data).

    Albahari writes about a theoretical situation where

    • StreamReader could return data to you (since it is in the buffer),
    • but found that there is space in the buffer and decided to read more data into the buffer just in case
    • called NetworkStream.Read
    • NetworkStream.Read blocked

    And you find yourself in a situation where it seems that the data you need came from, but the StreamReader is hanging and does not return anything, because wants more data from the stream.

    In practice (in the current implementation of StreamReader and NetworkStream ) this situation does not arise, because

    • StreamReader reads data from the input stream only if there is not enough data in the buffer to complete the requested operation.
    • NetworkStream.Read not blocked if at least some data is available.

    Those. locking will occur only in the case when the necessary data really did not come

    But implementation is one thing; there are no guarantees that it will not change.

    In fact, the problem is solved by the fact that the combination NetworkStream + StreamReader has no practical value. StreamReader adapted to work with pure text data. For example, he tries to look for a preamble (BOM) in a readable stream, and in general he uses the data itself to determine the ends of lines, which is wildly inconvenient when working with a network.

    Mixed data is usually transmitted over the network. For example, it is customary to transmit the same lines as <length> <text>, so as not to fall into the trap “it is not clear how much data was read and how long to wait”. For such work with streams it is more convenient to use BinaryReader .