views:

501

answers:

1

Currently, there isn't a NetworkStream.Peek method in C#. What is the best way of implementing such a method which functions just like NetworkStream.ReadByte except that the returned byte is not actually removed from the Stream?

+1  A: 

If you don't need to actually retrieve the byte, you can refer to the DataAvailable property.

Otherwise, you can wrap it with a StreamReader and invoke its Peek method.

Note that neither of these are particularly reliable for reading from a network stream, due to latency issues. The data might become available (present in the read buffer) the very instant after you peek.

I'm not sure what it is that you intend to do with this, but the Read method on NetworkStream is a blocking call, so you don't really need to check for status, even if you are receiving in chunks. If you are trying to keep the application responsive while reading from the stream, you should use a thread or asynchronous call to receive the data instead.

Edit: According to this post, StreamReader.Peek is buggy on a NetworkStream, or at least has undocumented behaviour, so be careful if you choose to go that route.


Updated - response to comments

The notion of a "peek" on the actual stream itself is actually impossible; it's just a stream, and once the byte is received then it is no longer on the stream. Some streams support seeking so you could technically re-read that byte, but NetworkStream isn't one of them.

Peeking only applies when are reading the stream into a buffer; once the data is in a buffer then peeking is easy because you just check whatever's at the current position in the buffer. That's why a StreamReader is able to do this; no Stream class will generally have its own Peek method.

Now, for this problem specifically, I question whether or not this is really the right answer. I understand the idea of dynamically selecting a method for processing the stream, but do you really need to do this on the raw stream? Can you not read the stream into a byte array first, or even copy it into a MemoryStream, and process it from that point on?

The main issue I see is that if something bad happens when you're reading from a network stream, the data is gone. But if you read it into a temporary location first, you can debug this. You can find out what the data was and why the object that was trying to process the data failed halfway through.

In general, the very first thing you want to do with a NetworkStream is read it into a local buffer. The only reason I can think of not to do this is if you're reading an enormous amount of data - and even then, I might consider using the file system as an intermediate buffer if it won't fit in memory.

I don't know your exact requirements, but from what I've learned so far, my advice would be: Don't try to process your data directly from the NetworkStream unless there is a compelling reason to do so. Consider reading the data into memory or onto disk first, then processing the copy.

Aaronaught
I do need to actually retrieve the byte. But I do not want it to be removed from the Stream since the byte contains information for deciding on using which method/class to further process the stream.
Lopper
So, get the byte, decide which method/class to use, then use it. Do you need the byte to still be in the stream after you decide? If so: bad protocol - using the same byte for two purposes.
John Saunders
@John Saunders: I totally agree, but I have dealt with devices (for which I don't control the protocol) that do exactly this. The first few bytes are a magic number and a content length, and these in turn need to be used to calculate a checksum that appears at the end. So even though it's a bad protocol, it is also, sadly, a real one.
Aaronaught
@Aaronaught: that's not a problem - I've dealt with that before. The issue would be one where half a byte is used for a message type, the other half is part of the message. In that case, you have to peek. But magic number and length can be read out, and passed to a factory method, along with the stream (containing `length`) more bytes.
John Saunders
@John Saunders: Indeed it can, which was the rationale behind my suggestion of reading it into a local buffer first. Another option would also be to only read just the header into a buffer, then pass that to the factory, which I think is what you're alluding to. I think I still prefer the former; doing any processing directly on a `NetworkStream` can be quite painful to debug...
Aaronaught