Re: server scenario - variables in the right spot?
- From: "David" <nospam@xxxxxxxxxx>
- Date: Fri, 8 Jun 2007 11:42:40 -0400
yes, very helpful, thank you.
I used below links to get me started... as you mentioned seeing also, thats
where I got the loop with the resetEvent to control incoming connections. I
just changed them to autoResetEvents because i didn't see why a manual was
needed (more code).
http://msdn2.microsoft.com/en-us/library/5w7b7x5f(vs.80).aspx
http://msdn2.microsoft.com/en-us/library/fx6588te(VS.80).aspx#Mtps_DropDownFilterText
http://msdn2.microsoft.com/en-us/library/bew39x2a(VS.80).aspx
these examples do use the waithandle events but I understand that it is
likely just to keep the code short in order to just illustrate the point at
hand... I didn't realize this and so used them.
- ConnectCallback calling beginAccept again instead of loop with
waithandles. No problem. Got it.
- ReceiveCallback calling beginReceive again: I do this but not exactly how
you illustrate, I first check if there is more data to receive and only do
it then. But I now understand what you are saying about always being ready
to receive (calling beginReceive immediately inside the ReceiveCallback).
This seems like an important modification I need to consider. But it has a
domino effect on my whole structure, of course. If i'm understanding this
correctly (a big 'if' hehe), then I would need to change my 'protocol' by
embedding 'control' information in order to keep things in order. For
example: currently, i'm just sending back and forth the 'commands',
'parameters' needed by those commands, and the 'results' of running those
commands. The 'control' of this happening is within my programs sequential
execution, whereas what I envision what you are saying is more or less a
perpetual sending/receiving motion where within the data received would lie
what it is, what to do with it, where you are in a multi-step process etc...
to try to illustrate (what I'm doing now) (just the connection-specific
stuff, client-server communication, assume this is CommandA which has a few
steps, assume everywhere I say 'wait' i mean using an autoResetEvent, all
sends and receives use the async begin*)
- client sends commandA and waits for confirmation from server of its
receipt
- server receives command and after verifying it can work with it, send back
confirmation of it's receipt and waits for next part
- client receives confirmation of command's receipt from server so *now
knows* it can send, lets just say, part2 of commandA, it sends and waits for
confirmation
- server receives part2 of commandA and sends back confirmation of receipt
and begins executing commandA
- client receives server's confirmation of receipt of part2 of commandA and
waits for results
- server finishes executing and send results back to client
- client receives results
assume there are some commands that may have more than 2 parts (trying to
keep example short). The 'control' in this case is my code on both sides
sequentially going through those steps. Now, with this perpetual
send/receive machine (that sounds cool) I'm envisioning the 'control' having
to be within the data sent so that it would be something like:
- server receives data, breaks it down per the protocol determining that it
is part2 of commandA already in progress, and proceeds appropriately. Like a
big switch statement based on the 'command' part of the protocol, then
within that case, potentially another switch statement or other control
structure for the particular 'part' of the command or where in the commands
total process the data belongs. This way there is no waithandles and control
is removed from the thread where it was and placed in the protocol, allowing
this 'perpetual machine' to run.
does this sound like I'm getting it?
well, either way, I appreciate your help. Sorry my posts are so long but I
don't know any other way to get out my thoughts/questions. I realize what I
really should do is go get a good book specifically on async network
programming for .net. I did read a .net network programming book but it was
for beginners, which I am, but didn't go into nearly enough detail on asynch
pattern to actually use it effectively.
"Peter Duniho" <NpOeStPeAdM@xxxxxxxxxxxxxxxx> wrote in message
news:op.ttkr7xaj8jd0ej@xxxxxxxxxxxxxxxxxxxxxxx
Well, I was going to point you to the Socket samples on MSDN (there are
links to them at the bottom of the Socket.BeginReceive method page, for
example), but after looking at them I'm not sure they are the best place
to look for guidance. For one, they have the same funny "while(true){
accept code with a waitable event }" paradigm you had in your code, and
for another they have a bug in the sending code in which they don't check
the number of bytes sent.
But the samples *do* illustrate what I was talking about, with respect to
posting a new receive or send within the callback for the one being
handled. So I suppose that counts for something. Now, all that said, you
had a specific question in there somewhere. Let's see if I can remind
myself where it was... :)
On Thu, 07 Jun 2007 14:11:31 -0700, David <nospam@xxxxxxxxxx> wrote:
thanks Peter. I figured I wasn't using the async model correctly. I'm
having
a hard time visualizing how the client-server conversation looks (in
code)
when done as you suggest (without waithandles). Inevitably there is a
conversation in which one side can't take the next step until an answer
is
received. So how is this 'wait' handled using asynch api as its supposed
to
be used?
Both sides can be waiting to receive at the same time, even as one side is
also doing something else (like preparing to send, and then sending).
That's the beauty of the asynch mechanism. You just provide the Socket
class with a buffer where it can put data, and then if and when it gets
data, it puts the data there and tells you about it. Likewise for
sending, you give it a buffer where it gets data, and then when it's
finished sending at least some of the data, it tells you about it and you
send whatever more data needs to be sent (which could be the remainder of
the data you tried to send earlier, or some new data, or none at all).
It's hard for me to give a specific example, since your original code was
sort of a mix of actual code and pseudocode. But as the general idea
goes, here's a sample of what the server might look like (also pseudocode,
so I don't have to bother looking everything up at the moment :) ):
void StartServer()
{
create a listening socket
call Socket.BeginAccept()
}
void AcceptCallback()
{
call Socket.BeginAccept() on the listening socket
call Socket.EndAccept() with current AsyncResult to get the
connected socket
call Socket.BeginReceive() on the connected socket
optionally, call Socket.BeginSend() on the connected socket to
send data to the client (you would skip this if the client is expected to
initiate the conversation)
}
void ReceiveCallback()
{
call Socket.BeginReceive() on the connected socket
call Socket.EndReceive() with current AsyncResult to get the
latest data
append the received data to your buffer, and if you've gotten
enough data to do something with, do it (make sure you don't lose track of
any extra data you might have received that would be part of a subsequent
transmission...if your protocol is strictly alternating, this shouldn't
normally be a problem)
NOTE: if your processing is inexpensive, you may in fact find
yourself doing it right here, and if so that processing may in fact lead
to your code calling Socket.BeginSend from within the receive callback.
There's nothing wrong with doing that at all.
}
void SendCallback()
{
call Socket.EndSend() with current AsyncResult to see how much
data was sent
subtract the number of bytes sent with the number of bytes you
need to send; if the result is greater than zero, you still have more data
to send, and so call Socket.BeginSend() to do that.
}
The client would be very similar, except that instead of a StartServer()
method, it would have a ConnectServer() method where it calls
BeginConnect() instead of BeginAccept(). Instead of the AcceptCallback()
method it would have a ConnectCallback() method, but the internals would
be very similar; there would be no reposting of the BeginConnect() of
course, but you would call BeginReceive() as well as possibly BeginSend(),
if the client is the one expected to initiate the conversation in your
protocol).
One thing I'll point out in the above is that the way I've written it, the
first thing I do in the accept and receive methods is post another one.
*Before* finishing the most recent one. I realize this may seem like more
confusion on top of what might already be a bit confusing. :) You can,
if you like, put the new calls to BeginAccept() and BeginReceive() at the
end, but I have read posts from people who when doing that have seen
performance suffer (and in the case of UDP, actually seeing more data
being lost than would be normal). There's no harm in posting multiple
receives, and in fact this is not uncommon in the native Winsock use of
i/o completion ports (on which the Socket class is based).
Because the above is just pseudocode, it should be apparent that a lot of
details are left out. In particular, you have to write code to manage
your send and receive buffers, to keep track of how much data you are
trying to send or receive, where that data is, and how much has been sent
or received so far. But those are fairly basic details, and not relevant
to the bigger picture of how the async stuff works.
[...] it seems my head needs that
'control' or 'main' thread to keep things straight. For example, in some
cases my beginReceive callback posts another beginReceive until all data
is
received, but its another thread that started that receive operation in
the
first place and is waiting to do something with what is received...
Well, the point of the above is that you are *always* ready to receive,
even if you haven't done anything yet for which you'd expect to be able to
receive. There's no harm in being ready to receive, and presumably at the
point in which you do something (like send data to the other end) that
would cause data to be sent back to you, your data structures are set up
to be ready to handle that case. That way in the receive callback, it can
just handle the received data normally.
Hope that helps.
Pete
.
- Follow-Ups:
- Re: server scenario - variables in the right spot?
- From: Peter Duniho
- Re: server scenario - variables in the right spot?
- References:
- server scenario - variables in the right spot?
- From: David
- Re: server scenario - variables in the right spot?
- From: Peter Duniho
- Re: server scenario - variables in the right spot?
- From: David
- Re: server scenario - variables in the right spot?
- From: Peter Duniho
- server scenario - variables in the right spot?
- Prev by Date: Re: Casting to double in C#
- Next by Date: Re: Retreiving the logon account username for a particular windows service
- Previous by thread: Re: server scenario - variables in the right spot?
- Next by thread: Re: server scenario - variables in the right spot?
- Index(es):