Socket.Available not right?

  • Thread starter Thread starter Ryan Petrie
  • Start date Start date
R

Ryan Petrie

Hello all,

Is it possible for Socket.Available to lie -- that is, is it possible
for the following to fail?

byte[] data = new byte[socket.Available];
int bytesRead = socket.Receive(data);
Debug.Assert(bytesRead == data.Length);

It appears that's exactly what's happening for me. I'm using one
routine (=one thread) to handle multiple connections. It does a
Socket.Select() on all sockets, and then for each socket with pending
data, it reads from the socket the amount of bytes returned by
socket.Available(). It stores it in a temporary buffer until the number
of bytes I expect arrive, at which point it's deserialized and queued up
for processing by another thread.

Sometimes, though, when several small messages are coming in at a time,
less bytes are actually received (as returned by Socket.Receive()) than
Socket.Available reported just a line or two of code previously. What
gives?

Incidentally, I tried ignoring that fact and continuing on, hoping the
data would come in the next read. But unfailingly I get a
SerializationException, suggesting to me that data really was lost.

Thanks in advance,
Ryan
 
Ryan Petrie said:
Is it possible for Socket.Available to lie -- that is, is it possible
for the following to fail?

<snip>

I've always thought that using Available is a risky business - mainly
since it bit me in early Java code I wrote (which probably had loads of
other things wrong with it).

However, I *wouldn't* expect any data to actually get lost.

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
Jon said:
I've always thought that using Available is a risky business - mainly
since it bit me in early Java code I wrote (which probably had loads of
other things wrong with it).

I found this article to support what you said:
http://support.microsoft.com/default.aspx?scid=kb;en-us;192599

It appears that Available is implemented in terms of FIONREAD, which the
above says is a no-no.
However, I *wouldn't* expect any data to actually get lost.

Also according to that article, there's an 8k buffer to store incoming
data. Perhaps that was getting filled... That's about all I can figure.
Could you post a short but complete program which demonstrates the
problem?

I wish that I could. I've been unable to duplicate it, and the problem
only happens on a client's machine. (eep!)

For now I plan to rewrite it to avoid Available (as it's not necessary
anyway) and use Socket.Poll() without a timeout of 0 where needed instead.

Thanks for the input,
Ryan
 
Ryan Petrie said:
I found this article to support what you said:
http://support.microsoft.com/default.aspx?scid=kb;en-us;192599

It appears that Available is implemented in terms of FIONREAD, which the
above says is a no-no.


Also according to that article, there's an 8k buffer to store incoming
data. Perhaps that was getting filled... That's about all I can figure.

Right. That would suggest that Available would return at most 8K, even
if more was sort-of available - but you shouldn't end up getting *less*
data. Still, probably best to avoid it :)
I wish that I could. I've been unable to duplicate it, and the problem
only happens on a client's machine. (eep!)

For now I plan to rewrite it to avoid Available (as it's not necessary
anyway) and use Socket.Poll() without a timeout of 0 where needed instead.

Any reason not to just call Receive for synchronous reading or
BeginReceive for asynchronous?
 
Jon said:
Right. That would suggest that Available would return at most 8K, even
if more was sort-of available - but you shouldn't end up getting *less*
data. Still, probably best to avoid it :)

Yeah, I don't know why, but it happened consistently on a client's
machine. My best guess is that I wasn't pulling data out fast enough.
Any reason not to just call Receive for synchronous reading or
BeginReceive for asynchronous?

That's what I'll do. My code will look something like this
(off-the-cuff code here):

class DataBlock
{
public byte[] data;
public int position;
}

// ...

while(!Closed)
{
// get a list of sockets with data to be read
ArrayList readList = GetSockets();
Socket.Select(readList, null, null, 1000000);

foreach(Socket socket in readList)
{
do
{
// get current DataBlock, or create a new one if necessary
DataBlock block = GetDataBlock(socket);

// read data
int bytesToRead = block.data.Length - block.position;
int bytesRead = socket.Receive(block.data, block.position,
bytesToRead, SocketFlags.None);

// process data
if (bytesToRead == bytesRead)
ProcessMessage(block);

} while (Socket.Poll(...));
}
}

Thanks again for the help,
Ryan
 
Ryan Petrie said:
Yeah, I don't know why, but it happened consistently on a client's
machine. My best guess is that I wasn't pulling data out fast enough.

Hmm... still shouldn't have lost data though :(
That's what I'll do. My code will look something like this
(off-the-cuff code here):

<snip>

Do you particularly need to use Poll and synchronous execution though?
Why not just call BeginReceive on each socket to start with, and let IO
completion ports sort it out for you?
 
Back
Top