Search code examples
c#networkstreambufferedstream

Why would BufferedStream.Write throw "This stream does not support seek operations"?


This one puzzles me. I get an error about seek when I'm not even calling it?

I have code that looks something like this:

// send 42
uint value = 42;
byte[] msg = BitConverter.GetBytes(value);
stream.Write(msg, 0, sizeof(uint));

and I get this exception:

System.NotSupportedException was unhandled
Message="This stream does not support seek operations."
Source="System"
StackTrace:
   at System.Net.Sockets.NetworkStream.Seek(Int64 offset, SeekOrigin origin)
   at System.IO.BufferedStream.FlushRead()
   at System.IO.BufferedStream.Write(Byte[] array, Int32 offset, Int32 count)
...

stream is of type System.IO.BufferedStream. What could possibly be going on?

edit with more info:

sizeof(uint)==msg.length in this case.
The stream is declared as stream = new BufferedStream(new NetworkStream(socket), 1024)

edit:

That was it! While one can read and write on a single NetworkStream, when switching to a BufferedStream it is necessary to have a separate one for reading and writing. One can apparently just call the NetworkStream constructor twice on the same socket to get that.

I'd accept both Justin and Hans' answers if I could, because one let me exactly understand what was wrong, and the other led me to the solution. Thanks everyone!


Solution

  • The problem lies in the inner workings of BufferedStream (and the fact that you may have used the BufferedStream to Read from prior to attempting to write to it).

    When you try to Write to a BufferedStream, after validating your parameters, things are checked in this order (all code pulled from the Framework via Reflector):


    Are we at the begging of the write buffer?

    if(this._writePos == 0)
    

    Are we allowed to write to the underlying stream?

    if(!this._s.CanWrite) // throw error
    

    Is the Read buffer empty?

    if(this._readPos < this._readLen)
    {
        // FlushRead() will attempt to call Seek()
        this.FlushRead();
    }
    

    If there is unread data in the read buffer, a Flush is attempted before writing. FlushRead() calls Seek(), which is what is causing your error.