Are there an alternative to System.IO.BufferedStream in C#?
-
23-08-2019 - |
Question
I receive the follow exception:
System.NotSupportedException : This stream does not support seek operations.
at System.Net.Sockets.NetworkStream.Seek(Int64 offset, SeekOrigin origin)
at System.IO.BufferedStream.FlushRead()
at System.IO.BufferedStream.WriteByte(Byte value)
The follow link show that this is a known problem for microsoft. http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=273186
This stacktrace show 2 things:
- The System.IO.BufferedStream do some absurd pointer move operation. A BufferedStream should buffer the underlying stream and not more. The quality of buffer will be bad if there are such seek operation.
- It will never work stable with a stream that not support Seek.
Are there any alternatives? Does I need a buffer together with a NetworkStream in C# or is this already buffered.
Edit: I want simply reduce the number of read/write calls to the underlying socket stream.
Solution
The solution is to use two independent BufferedStream
s, one for receiving and one for sending. And don't forget to flush the sending BufferedStream
appropriately.
Since even in 2018 it seems hard to get a satisfying answer to this question, for the sake of humanity, here are my two cents:
The NetworkStream
is buffered on the OS side. However, that does not mean there are no reasons to buffer on the .net side. TCP behaves well on Write-Read (repeat), but stalls on Write-Write-Read due to delayed ack, etc, etc.
If you, like me, have a bunch of sub-par protocol code to take into the twentyfirst century, you want to buffer.
Alternatively, if you stick to the above, you could also buffer only reads/rcvs or only writes/sends, and use the NetworkStream
directly for the other side, depending on how broken what code is. You just have to be consistent!
What BufferedStream
docs fail to make abundantly clear is that you should only switch reading and writing if your stream is seekable. This is because it buffers reads and writes in the same buffer. BufferedStream
simply does not work well for NetworkStream
.
As Marc pointed out, the cause of this lameness is the conflation of two streams into one NetworkStream which is not one of .net's greatest design decisions.
OTHER TIPS
The NetworkStream is already buffered. All data that is received is kept in a buffer waiting for you to read it. Calls to read will either be very fast, or will block waiting for data to be received from the other peer on the network, a BufferedStream will not help in either case.
If you are concerned about the blocking then you can look at switching the underlying socket to non-blocking mode.
A BufferedStream
simply acts to reduce the number of read/write calls to the underlying stream (which may be IO/hardware bound). It cannot provide seek capability (and indeed, buffering and seeking are in many ways contrary to eachother).
Why do you need to seek? Perhaps copy the stream to something seekable first - a MemoryStream
or a FileStream
- then do your actual work from that second, seekable stream.
Do you have a specific purpose in mind? I may be able to suggest more appropriate options with more details...
In particular: note that NetworkStream
is a curiosity - with most streams, read/write relate to the same physical stream; however, a NetworkStream
actually represents two completely independent pipes; read and write are completely unrelated. Likewise, you can't seek in bytes that have already zipped past you... you can skip data, but that is better done by doing a few Read
opdrations and discarding the data.