One possibility would be if you pump messages while in a OnReceive call.
For example, calling MessageBox does this. If the timing is just
wrong, pumping messages while in OnReceive will cause OnReceive to
reenter. Depending on your code, the reentered version might never call
Receive, so notifications stop. Check for OnReceive reentry.
--
Scott McPhillips [VC++ MVP]
Are you certain that your last call to Receive is returning SOCKET_ERROR
with a WSAGetLastError of WSAEWOULDBLOCK? If it's not, then you won't be
getting any further FD_READs unless you somehow re-trigger the entire
mechanism.
Sometimes you can be too smart about recv's: you know exactly how much data
you expect to receive and you ask only for that precise amount. This causes
a problem in that a call to recv will not result in an error of
WSAEWOULDBLOCK, and you will not get a FD_READ notification when new data
arrives later.
<danceswi...@hotmail.com> wrote in message
news:1110853800.5...@z14g2000cwz.googlegroups.com...
That's not correct. From MSDN WSAAsyncSelect:
"With these semantics, an application need not read all available data
in response to an FD_READ message—a single recv in response to each
FD_READ message is appropriate."
You're reading only part of the docs. (For the benefit of other, see
http://msdn.microsoft.com/library/en-us/winsock/winsock/recv_2.asp ). In
the section you quoted, the reason that the app continues to get FD_READs is
because a previous WSAEWOULDBLOCK is still valid. This is explained
slightly above the section you quoted, as follows (with a few editorial
comments and capitalizations inserted):
"For FD_READ, FD_OOB, and FD_ACCEPT events, message posting is
level-triggered [ed: as opposed to edge-triggered; this is important]. This
means that if the reenabling routine is called and the relevant condition is
STILL MET AFTER THE CALL [ed: important], a WSAAsyncSelect message is posted
to the application. This allows an application to be event-driven and not be
concerned with the amount of data that arrives at any one time. Consider the
following sequence:
"1. Network transport stack receives 100 bytes of data on socket s and
causes Windows Sockets 2 to post an FD_READ message.
"2. The application issues recv( s, buffptr, 50, 0) to read 50 bytes.
"3. Another FD_READ message is posted because there is STILL data to be
read.
"With these semantics, an application need not read all available data in
response to an FD_READ message—a single recv in response to each FD_READ
message is appropriate. If an application issues multiple recv calls in
response to a single FD_READ, it can receive multiple FD_READ messages. Such
an application can require disabling FD_READ messages before starting the
recv calls by calling WSAAsyncSelect with the FD_READ event not set."
So, FD_READ is level-triggered as opposed to FD_QOS (and others) which is
edge-triggered. To see the distinction, here's what the docs say about
FD_QOS:
"The FD_QOS and FD_GROUP_QOS events are considered edge triggered. A message
will be posted exactly once when a quality of service CHANGE [ed] occurs.
Further messages will not be forthcoming until either the provider detects a
further CHANGE [ed] in quality of service or the application renegotiates
the quality of service for the socket."
But you're correct that my post might have been so general that it was
misleading. It should have stated that an FD_READ notification is sent
"only after you have tried to read but failed with WSAEWOULDBLOCK, or after
a succesful read but only if the conditions that caused a prior
WSAEWOULDBLOCK are still valid".
These criteria are *very* slippery, but I THINK I get what you are
saying. If 100 bytes arrive, but after a read some of those 100 bytes
are still there, another notification will be posted. However, if all
those 100 bytes are read, and no other read attempts are made, no more
FD_READ notifications are posted, is that right?
>
> "With these semantics, an application need not read all available
data in
> response to an FD_READ message-a single recv in response to each
But this I don't understand. The "if the conditions that caused a
prior WSAEWOULDBLOCK are still valid" is confusing. It appears to
conflict with "after a succesful read". There's only one condition I'm
aware of that would cause a WSAEWOULDBLOCK on a read, and that's if
there is nothing available. So if a read is successful (assuming that
"successful" means reading bytes, without error) and empties the
receive buffer, then a notification would be posted since the condition
that causes WSAEWOULDBLOCK (nothing in the buffer) is valid. Naturally,
a read would be attempted, WSAEWOULDBLOCK would be returned, which you
say is sufficient to cause a future notification when new data comes
in. This is obviously not what's happening, since my transfers stall.
Unfortunately, I could not find a definitive answer.
So, the upshot is that while I *think* I'm correct, I also found enough
contradictory information so that I could be persuaded that I'm wrong.
For example, look at pages 20-22 of the following pdf file:
http://course.ie.cuhk.edu.hk/~ieg4180/lecture/Lecture%202004-2005/04-message_driven_sockets_programming.pdf .
It shows examples of level triggering and edge triggering, for FD_READ and
FD_WRITE, that act exactly the way that Scott McPhillips said, and are
exactly opposite to the way that I understand it.
Sorry for the controversy.
Mike
<danceswi...@hotmail.com> wrote in message
news:1110907561.0...@l41g2000cwc.googlegroups.com...
It's hard to believe that information so crucial would be so
unavailable. I think the last time I tried to Receive() until I got a
WSAEWOULDBLOCK, I had problems. Then I was told that anytime Receive()
is called, a notification would be posted the next time there is data
available (or immediately, if there is data left).
So I'm back to asking anyone if there is a better solution than my
workaround? This workaround being a CWnd timer that triggers every few
seconds, and does a MSG_PEEK on the socket, which wakes up the sleeping
socket.
I have built lots of CAsyncSockets, both heavily and lightly loaded, and
have not ever had this problem. The symptoms you have correspond to
missing one FD_READ notification (somehow). If you miss one the
back-and-forth handshake stops.
(One FD_READ should be generated after every call to Read.
WSAEWOULDBLOCK should not occur, since OnReceive is only called if data
is available.)
Since you ruled out reentry to OnReceive, all I can suggest is to
simplify your code to a drastically cut down test version in an attempt
to isolate the source of the problem.
Simplifying the code isn't possible. It's already simple enough
that I can be sure that for every OnReceive() call a Receive() is also
called. I guess I could look into the possibility that I'm trying to
Receive() 0 bytes (if such a thing could jam the socket up) but I doubt
that's it. I guess it's time to concede that I have more important
things to attend to, and accept my workaround. Thanks anyway.