Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the stream not support the seek operation?

I'm currently working with tcp/ip suite. I'm writing a program to encrypt files at sender's end and decrypt at receiver's side. I came across this exception while initializing my byte array with the length that of network stream. Here's my code:

if (client.Connected)
{
    NetworkStream binarystream = client.GetStream();
    byte[] receivebytes = new byte[binarystream.Length];
    binarystream.Read(receivebytes, 0, receivebytes.Length);
    Stream file = File.OpenWrite(saveFileDialog1.FileName);
    file.Write(receivebytes, 0, receivebytes.Length);
    file.Close();
    binarystream.Close();
}

The hierarchy of control ensures that the stream returned by client.GetStream() will have already been used for before making up binarystream instance. The exception I'm getting is on the line containing:

byte[] receivebytes = new byte[binarystream.Length];

It says that the stream doesn't support the seek operation. What does that mean?

like image 688
Jawad Avatar asked Apr 27 '14 09:04

Jawad


2 Answers

It is the normal state for a Stream. You need to mentally model it like a small desert river in the spring, trickling water like a Stream is trickling bytes. You don't know when it is going to dry up, that requires a weather forecast that faithfully predicts when it is going to stop raining.

Such weather forecasts certainly exist. No trouble if it is actually a MemoryStream, it has access to all the bytes so it can reliably tell you when it dries up. Or a FileStream, now the operating system's file system can provide the forecast. The directory entry for the file data records the length of the file.

It gets to be a lot harder for TCP streams. The TCP protocol itself doesn't provide the information at all. You can only keep calling the socket's Read() method and when it returns 0 then you know it stopped raining.

This often requires building a protocol on top of TCP. The very common HTTP protocol is a good example. It does provide you with the forecast, it is HttpWebRequest.ContentLength. Or you make your own, the standard technique is to have the transmitter first write 4 bytes that says how much data follows. But NetworkStream doesn't cater to specific protocol implementations, it models a generic network stream. You have to add the weather forecast yourself.

like image 126
Hans Passant Avatar answered Oct 31 '22 19:10

Hans Passant


To determine the length of a stream, you need to be able to read to the end of it (i.e. you Seek to the end). Since this is a network stream, you can't just do this, hence the error you're experiencing. You will need to just keep reading bytes into a buffer until the stream ends, and only then will you know the length of your payload. Here's a suggestion:

if (client.Connected)
{
    NetworkStream binarystream = client.GetStream();
    Stream file = File.OpenWrite(saveFileDialog1.FileName);

    byte[] buffer = new byte[10000];
    int bytesRead;
    while (binarystream.DataAvailable)
    {
        bytesRead = binarystream.Read(buffer, 0, buffer.Length);
        file.Write(buffer, 0, bytesRead);
    }

    file.Close();
    binarystream.Close();
}

Note that I would also recommend adding using statements for each of your stream instantiations, as this guarantees that the streams will be closed properly even if an exception is thrown while reading/writing. You could then remove the explicit calls to Close.

like image 23
Simon MᶜKenzie Avatar answered Oct 31 '22 18:10

Simon MᶜKenzie