Async Socket Question

  • Thread starter Thread starter Paul M. Seabury
  • Start date Start date
P

Paul M. Seabury

I have read the MSDN docs, many examples, and even coded some async
client/servers. My question is this. How do you know when the data you are
expecting has arrived? I understand that when EndReceive() returns 0, there
is no more data to read. But what if there is really more data coming, it
just hasn't arrived yet? A small example.

Suppose I want to write a basic XML server. The server reads and writes XML
documents to transfer data. Suppose I have the usual Asnyc setup with a
1024Byte receive buffer, and a state object with a string (or stringbuilder)
member that keeps track of all the data thus received from a particular
socket. How do I know that I've gotten an entire XML doc? What if the doc
is a few MB big and a call to EndReceive returns 0 because the sender has
stalled? Maybe I get half the doc, then sender stalls, my Async callback
returns 0 on endreceive because there is no more data at that instant. Is
that how it works? Do I need to try and validate the doc (in my state
object) every time my callback returns to see if the entire doc has arrived?
This just degrades to polling if that is the case. Any enlightenment would
be greatly appreciated. Sorry about all the questions, but I cannot (thus
far) understand how you know when all of the data the client intends to send
has arrived. Obviously if the client closes the socket I will know, but
what if he/she keeps the tcp stream open and periodically sends XML docs my
way?

Thanks in advance,

Paul Seabury
Elantech Inc.
(e-mail address removed)
 
Paul, sockets are not all that simple.
Zero bytes received does not indicate end of message. You will only receive
zero bytes if an error occurred, or the sender socket was closed, or on
timeout (timeout if you set timeout calling SetSocketOption). If the sender
sends 500 bytes, your read will return 500, then it won't return until one
of the above conditions occur, even though the sender sends nothing else.
Here is some more bad news, because sockets are stream orientated (not
message), if the sender sends 2 messages fast (lets say 1000 bytes each),
depending on conditions on the client/server/network, you may receive 500
bytes of the 1st message (even though the read specified 1024 for example),
then the next read may receive 1024 bytes, which is the rest of the 1st
message plus the 1st part of the 2nd message.

There are 2 solutions.
1. The sender opens the socket, sends the total message and closes the
socket, so the receiver knows the message is completed (you will receive 0
bytes at the end, because the sender socket closed).
2. Put a length field in front of every msg (say 1st 5 bytes is length). Be
careful not to ask for example for 1024 bytes with every read, as you may
read past the 1st message end, or if you do, you will have to un-buffer the
messages yourself.

HTH,

Chris.
 
Thank you very much Mr. Botha. I have to say, OUCH, that hurts. All I can
say is that there must be some sort of method for determining when a single
'message' has arrived. Look, for example, at a simple asynchronous http
proxy. If you specify it as a http1.1 compliant proxy, then you are pretty
much guaranteed to get rapid-fire requests thrown your way. If your buffer
is for the sake of this argument, 256 bytes, so that you have requests
overlapping your buffer all the time...how in the heck do you know when an
entire well-formed request has come without trying to validate it every time
you hit your callback method? That seems like a lot of overhead. Creating
a new connection every time you pass a message seems hideous too. I
obviously don't have a handle yet on .NET's and asynchronous sockets in
general, but I'm trying. Hopefully with some more help from people like Mr.
Botha I'll figure this out.

Let me explain in general terms on more time what I am trying to do. I want
to make a general base server class that I can extend. The requirement for
the the base server is that it provide a virtual method to process XML
documents (received from clients) and send XML docs as responses. XML will
be validated against a schema for any particular flavor of server. Say a
TimeServer that extends XMLServer...or a FooServer that extends XML server.
The beauty is that all inherited classes only need to override the virtual
method to process the XML doc for whatever purpose they serve. Very useful
indeed.

Is it a guarantee (or a safe bet even), that if the async EndReceive()
returns less than the buffer size then the end of that atomic 'message' has
been reached? For instance if ClientA first sends a 1280Byte XML doc, and
then a 768Bytes XML doc, and the server's buffer is 1024Byte, then do I get
....

Server reads 1024..
Server reads 256..
Server reads 768.

or possibly

Server reads 1024
Server reads 1024

Thanks again for your reply Mr. Botha.

Paul M. Seabury
Elantech Inc.
(e-mail address removed)
 
The easis way to you is to implement comands and specify data size.

For example:

client: put fileName 1000
server: reads 1000
Then you just read 1000 bytes in server, or if you won't get these bytes,
probably socket was closed.

client: get file
server: OK 1000 or server: ERR no such file

This solution is smallest overhead and simpliest way to be sure that you get
full message.

Also you may add md5 hash value parameter of file, which you can use stored
or retrived file was 100% successfull.
 
Back
Top