tags:

views:

754

answers:

2

How does read(buffer, offset, length) actually work, if i pass the length to read as 32, does that mean that it would keep blocking till it receives the 32 bytes?

I understand it would return and exception or 0 in case of socket exception or if the connection is closed, respectively.

what if the sender only sends 31 bytes , would read continue to block? if that is true, does it mean that read would always return the integer that is equal to length passed to it? and also how cnan i control the timeout if the remaining 1 byte does not come after certain time.

Important and yet not answered

In contrast, what if the sender sends 32 byte , does that assure that read would block until all 32 are received or can it come out without reading all the 32 bytes.

+3  A: 

No, it will not block. The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter. Source: http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.read.aspx

Given it will not wait for that extra 1 byte, if you are expecting it, you should implement a loop to continue reading the stream. You can exit the loop however you feel best.


UPDATE: I was wrong when I stated "There's no blocking at all. If no data is available for reading, the Read method returns 0", but I was correct when I stated that it wouldn't block waiting to fill the entire buffer which it the scenario described in Kazoom's question.

Updated to demonstrate that NetworkStream.Read blocks waiting for the first byte, but does not block waiting to fill the entire buffer.

Create to console projects

On one end, you have the listener:


IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345);
TcpListener listener = new TcpListener(ep);
listener.Start();
TcpClient client = listener.AcceptTcpClient();
NetworkStream s = client.GetStream();
byte[] buffer = new byte[32];
Console.WriteLine(s.Read(buffer, 0, 32));
Console.WriteLine("Press any key to continue...");
Console.Read();

On the other end, we send only one byte:


IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345);
TcpClient client = new TcpClient();
client.Connect(ep);
client.GetStream().Write(new byte[] { 60 }, 0, 1);
Console.WriteLine("Press any key to continue...");
Console.Read();

Both sides will run until they reach Console.Read(). Notice that the listener does not block on Read.

The listener will print "1"

Alfred Myers
so it blocks at byte level and not bit level
Kazoom
There's no blocking at all. If no data is available for reading, the Read method returns 0.
Alfred Myers
what do we mean by no data available, what if the sender send 32 bytes does that guarantees that read would only return after reading those 32 bytes, (considering that this is a tcp connection)
Kazoom
You are incorrect. It does not state that it will block, but it will just like any other socket read.
scottm
I'll have to find some code I wrote a couple of years ago. From what I remember I had to put Read inside a loop because there were circumstances when I did not receive all bytes I was expecting at once. I'll get back to you.
Alfred Myers
@scottm: You have to put what I mean in context. It will block while reading from the underlying buffer. That's why theres a method called BeginRead . **But it will not block waiting for the extra 1 byte Kazoom stated in his example.**
Alfred Myers
@ ALfred, yes it will. Try the async code I posted, change the byte array sent to 31 instead of 32 and watch it happen.
scottm
@scottm: As my code demonstrates, I expected 32, receive 1 and it returned. It only blocks when nothing is sent at all, so I guess we were both wrong.
Alfred Myers
@Alfred, you are right. I did some more research and updated my answer. It really has to do with the implementation of Stream.Read().
scottm
+1  A: 

It will block until it receives 32 bytes, or the connection is closed. The async methods BeginRead() and EndRead() should be used to provide non-blocking reads.

Here is some example code clearly demonstrating the blocking effect.

   Socket one = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    Socket two = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345);

    one.Bind(ep);
    one.Listen(1);
    two.Connect("127.0.0.1", 12345);
    one = one.Accept();

    NetworkStream s = new NetworkStream(two);
    byte[] buffer = new byte[32];
    s.Read(buffer, 0, 32);

Edit

Even though this code produces the blocking effect, it's only because of NetworkStream's implementation of Stream's abstract Read() method (which must be overridden). The documentation on Stream.Read() states this:

Implementations return the number of bytes read. The return value is zero only if the position is currently at the end of the stream.

Which is why the code blocks when NO data has been received AND the end of the stream has not been reached. It also goes on to say:

The implementation will block until at least one byte of data can be read, in the event that no data is available. Read returns 0 only when there is no more data in the stream and no more is expected (such as a closed socket or end of file). An implementation is free to return fewer bytes than requested even if the end of the stream has not been reached.

scottm
http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.read(VS.71).aspx
Kazoom
just wondering why does the function need to return number of bytes read, instead it can just return the status of the read
Kazoom
@Kazoom, If you read 20 bytes and the connection is closed, the number returned is 20.
scottm
The question is what would happen if he received 31 bytes when he was expecting 32. You're first example is wrong. You **forgot** to accept the connection and you **forgot** to send at least one byte.
Alfred Myers
@Alfred, I updated my answer to add the accept in there. It still does not send the one byte, but that's explained in my edit.
scottm