10

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!

ken2k
  • 48,145
  • 10
  • 116
  • 176
redtuna
  • 4,586
  • 21
  • 35

2 Answers2

10

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.

Justin Niessner
  • 242,243
  • 40
  • 408
  • 536
  • ok, so I can't call write when there's unread data... which basically means I can't have one thread read and the other write on the same BufferedStream. Now, given that I have a NetworkStream when I connect to the other computer, how do I get two BufferedStreams from it? – redtuna Jun 22 '10 at 18:21
  • @redtuna - If that's your goal, you're going to have to create two NetworkStreams to match the two BufferedStreams. Otherwise you're going to run in to a whole host of issues with the shared NetworkStream. – Justin Niessner Jun 22 '10 at 18:30
5

You must have been reading earlier from that BufferedStream. It is getting its bytes from a NetworkStream. Those are one-way, you can either only read from or only write to them, depending how they were created. Post the code that created the NetworkStream if you need more help.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • You may be onto something: it's possible that another thread is trying to read at the same time, and that'd be the problem. The docs do say that you can both read and write from the same BufferedStream (and in the case of mine, both .CanRead and .CanWrite are true) but perhaps not at the same time. – redtuna Jun 22 '10 at 18:07
  • You should have two NetworkStreams and two BufferedStreams, if I'm understanding the point correctly. Read from one and write to the other. – Platinum Azure Jun 22 '10 at 18:11
  • @red: yes, BufferedStream supports reading and writing. But the stream it is reading/writing from might not support it. NetworkStream doesn't. – Hans Passant Jun 22 '10 at 18:21
  • My code isn't reading while writing - but Justin's answer indicates that having unread data is enough to get into trouble (and of course I have no control over that). Is there a way to connect once but get two BufferedStreams? – redtuna Jun 22 '10 at 18:23
  • @red: a NetworkStream opened for writing won't have unread data. I would first check if you are using the correct NS. Focus on the network streams, not the BufferedStream – Hans Passant Jun 22 '10 at 18:27
  • ok Hans, let me rephrase. I have a connected socket. Can I call new NetworkStream(socket) more than once? – redtuna Jun 22 '10 at 18:31
  • I'm going to stop guessing and insist you post a relevant code snippet. – Hans Passant Jun 22 '10 at 18:40
  • This comes from a rather large program; it was easier for me to change it to call the NetworkStream constructor twice than to extricate just enough code to get something that's actually runnable yet not too long (since I'm not sure what code you were looking for, beyond the construction of the NetworkStream that I already show in the question). But creating two NetworkStreams on the same socket appears to work, so - yay! – redtuna Jun 22 '10 at 18:48