Re: BeginReceive return zero length buffer when run ,and work correctly when use step by step debug mode
- From: "semedao" <semedao@xxxxxxxxxxxxxxxx>
- Date: Sat, 16 Sep 2006 12:32:48 +0200
Hi peter , when I used the sync methods it throw exception related to mixed
block-unblock sockets...
only for this reason I made those helper methods
If I use the loop and don't break when recv zero length - I enter inside
un-finished loop.
"Peter Duniho" <NpOeStPeAdM@xxxxxxxxxxxxxxxx> wrote in message
news:12gmjrgpioqlfe@xxxxxxxxxxxxxxxxxxxxx
"semedao" <semedao@xxxxxxxxxxxxxxxx> wrote in message
news:OCyEJLS2GHA.4116@xxxxxxxxxxxxxxxxxxxxxxx
Hi , I take back my words about missing data... :))
ok ok , the data is missing , but , help me understand
why ??
At what point is it missing? Do you ever try to read from the socket
again after getting a 0 return value from EndReceive and throwing an
exception? I think that's an important clarification.
firsy - yes , I am using TCP
now , If I made loop around the "beginRecv until it will return the
expected buffer length , the app is in infinite loop in case when the
return of endrecv is zero.
so , how can I handle it ?
oopsie on my part. I didn't notice you had the whole non-blocking
scenario wrapped in a do/while loop. I think your loop is fine (except
that it didn't include the blocking case), and should in fact keep control
within the loop until you've read sufficient data (as long as you don't
throw an exception, so the first step is to take that out as a response to
receiving a 0 return value).
Secondly, I would forget (at least for the moment) using Begin/EndReceive.
I think it's an unnecessary distraction, especially since you want your
code to block anyway. Use a regular Receive. With a non-blocking socket,
you'll want to also call Socket.Select to block your thread until data is
available on the socket. Since I haven't used .NET sockets, I don't
really know whether you're using the Begin/EndReceive functions correctly,
but they seem to me to be unneeded here, since you don't intend for your
thread to continue doing some other work after calling BeginReceive.
Third, I finally noticed a bug in your call to Receive, in which you fail
to update the buffer offset. I don't think this would cause the issue
you're asking about, but it's a serious problem.
Here's how I'd try to write it (note of course that not having used
sockets in .NET, I can't guarantee this is perfectly correct :) ):
public static byte[] Receive(Socket openSocket, int length)
{
byte[] buffer = new byte[length];
int totalreceive = 0;
do
{
int lastreceive;
/*
* For non-blocking sockets, the Socket.Select method will block
* the thread until there is actually data to be read from the
socket.
*
* If you want to get really picky, check to make sure your socket
* is still in the socklistRead list before trying to read from it.
* Since it's the only one that was in there to begin with, it
still
* should be and even if it's not the worst that can happen is we
* loop back around and try again.
*/
if (!openSocket.Blocking)
{
ArrayList socklistRead = new ArrayList();
socklistRead.Add(openSocket);
Socket.Select(socklistRead, null, null, -1);
}
/* Be prepared for an exception */
try
{
/*
* For blocking socket, this will block the thread until
* data is available. For a non-blocking socket, we hope
* that the data is still there after returning from
* Socket.Select, but it's no big deal if it's not (we'll
* get a WSAEWOULDBLOCK error and go back to try again).
*/
lastreceive = openSocket.Receive(buffer, totalreceive, length,
SocketFlags.None);
/*
* Sockets will return zero if the socket is
* closed and we've already read all the data on the socket
*/
if (lastreceive == 0)
{
throw new Exception("Socket was closed");
}
}
catch (SocketException exc)
{
/*
* WSAEWOULDBLOCK is a non-fatal error...we just need to
* go back and try again.
*/
if (exc.ErrorCode != WSAEWOULDBLOCK)
{
throw;
}
lastreceive = 0;
}
catch
{
throw;
}
/*
* At this point, we've received valid data, and it's been
* put into the buffer. Update our byte counter to reflect
* that.
*/
totalreceive += lastreceive;
length -= lastreceive;
} while (length > 0);
}
By the way, there is a Socket.Receive overload that takes an "out
ErrorCode" parameter. The docs claim that even this method returns an
exception in the case of a Winsock error, but I suspect that in reality
the function returns SOCKET_ERROR (-1) and sets the output parameter (this
would be consistent with how Winsock itself works). I didn't bother to
try it to see, since other exceptions can still happen anyway, but if it's
true that you can detect WSAEWOULDBLOCK that way instead, it might be
nicer to use that instead of having to use a try/catch block within the
loop. Instead of:
try
{...}
catch (SocketException...)
{...}
catch
{...}
You'd have something like this:
lastreceive = openSocket.Receive(..., err);
if (lastreceive == SOCKET_ERROR)
{
if (err != WSAEWOULDBLOCK)
{
throw new SocketException(err);
}
lastreceive = 0;
}
else if (lastreceive == 0)
{
throw new Exception("Socket was closed");
}
Note the extensive use of ellipsis' to denote code I didn't want to bother
typing out. :)
Anyway, I hope this helps. I'm making the (possibly incorrect) assumption
that the .NET version of sockets doesn't stray too far from the underlying
functionality. I essentially translated what I do know to be correct for
Winsock generally into the means and methods available in .NET. With some
luck, it'll be exactly what you need. :)
Pete
.
- Follow-Ups:
- References:
- BeginReceive return zero length buffer when run ,and work correctly when use step by step debug mode
- From: semedao
- Re: BeginReceive return zero length buffer when run ,and work correctly when use step by step debug mode
- From: Daniel
- Re: BeginReceive return zero length buffer when run ,and work correctly when use step by step debug mode
- From: semedao
- Re: BeginReceive return zero length buffer when run ,and work correctly when use step by step debug mode
- From: Peter Duniho
- Re: BeginReceive return zero length buffer when run ,and work correctly when use step by step debug mode
- From: Daniel
- Re: BeginReceive return zero length buffer when run ,and work correctly when use step by step debug mode
- From: Peter Duniho
- Re: BeginReceive return zero length buffer when run ,and work correctly when use step by step debug mode
- From: semedao
- Re: BeginReceive return zero length buffer when run ,and work correctly when use step by step debug mode
- From: Peter Duniho
- BeginReceive return zero length buffer when run ,and work correctly when use step by step debug mode
- Prev by Date: Re: BeginReceive return zero length buffer when run ,and work correctly when use step by step debug mode
- Next by Date: Re: Timer in a Windows Service not firing?
- Previous by thread: Re: BeginReceive return zero length buffer when run ,and work correctly when use step by step debug mode
- Next by thread: Re: BeginReceive return zero length buffer when run ,and work correctly when use step by step debug mode
- Index(es):
Relevant Pages
|