Re: server scenario - variables in the right spot?
- From: "Peter Duniho" <NpOeStPeAdM@xxxxxxxxxxxxxxxx>
- Date: Thu, 07 Jun 2007 16:44:11 -0700
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:
- 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
- server scenario - variables in the right spot?
- Prev by Date: Re: interfaces
- Next by Date: Re: Looking for Tips/Writeup on overall approach to Exception Processing
- Previous by thread: Re: server scenario - variables in the right spot?
- Next by thread: Re: server scenario - variables in the right spot?
- Index(es):
Relevant Pages
|