[Mono-list] Socket code.

Michal Moskal malekith@pld-linux.org
Mon, 23 Feb 2004 09:37:02 +0100


On Mon, Feb 23, 2004 at 10:21:06AM +0000, Jonathan Gilbert wrote:
> At 11:59 AM 22/02/2004 -0800, you wrote:
> >On Sun, 2004-02-22 at 01:17, Michal Moskal wrote:
> >> On Sat, Feb 21, 2004 at 04:31:00PM -0800, George Farris wrote:
> >> > I have some socket code that looks something like this:
> >> > 
> >> > byte[] bytes = new byte[1448];
> >> > do {
> >> > 	len = sock.Read(bytes, 0, (int)1448);
> >> > 	s = Encoding.ASCII.GetString(bytes);
> >> > 	buf.Append(s.Substring(0,len));
> >> 
> >
> >Interesting, this code will work as long as the check at the bottom is
> >1448, any other number and it croaks???  The buffer can be any size
> >presumably larger than 1448 and it will work.
> 
> Note (to original poster) that if you want to read up to the end of the
> stream, you should actually check 'len' against '0':
> 
>   if (len < 0)
>     error_occurred();
>   if (len == 0)
>     end_of_stream_occurred();

This ain't C -- for errors you should get exception, not -1.

> You shouldn't assume that the underlying transport will always be able to
> deliver chunks of the same size. The 1448 here has most likely to do with
> the sending computer's TCP/IP stack. Perhaps it ties the TCP packet size
> into the MTU to decrease fragmentation & increase performance (this is
> fairly common, as I understand). Assuming this is the case, your problem is
> simply evidence that, unlike my 'ReadFully' function,
> 'NetworkStream::Read()' does not try to completely read the requested
> buffer. Instead, it does one read attempt and then immediately returns. So,
> you're limited to the size that 'Socket::Receive()' will give you.

This is the same as read(2) Unix function. This is the only reasonable
thing to do -- there are cases when you don't want to block, so you
first check if data is available and then do read(). If read() wait for
entire buffer to be filled you would block anyway.

> In short, any positive value from 'Socket::Receive()' indicates that there
> could be additional data waiting; a return value of 0 indicates that the
> connection was shut down in that direction (thus indicating the
> end-of-stream). Simply getting a smaller value than you requested does not
> indicate that the end of the stream has been reached. This is distinctly
> different from file I/O.

Again, I'm not sure about .NET class library, but for Unix file I/O
read() can return less then requested, and it still wouldn't indicate
end of file. If you wonder why, consider pipes that are also files.

-- 
: Michal Moskal :: http://www.kernel.pl/~malekith :: GCS !tv h e>+++ b++
: When in doubt, use brute force. -- Ken Thompson :: UL++++$ C++ E--- a?