Re: Async TCPClients



"Dave Sexton" <dave@jwa[remove.this]online.com> wrote in message
news:OeNG0D9kGHA.5072@xxxxxxxxxxxxxxxxxxxxxxx
Hi Shak,

Inline:

If you are worried about blocking a ThreadPool thread then spawn your
own Thread and use synchronous NetworkStream calls.
But I wouldn't worry about it anyway. Just don't call EndRead while on
a ThreadPool thread because nested ThreadPool calling may cause a
deadlock. i.e. don't execute asynchronously on a ThreadPool thread to
make another asynchronous call on another ThreadPool thread (this may
cause a dead-lock).

Do you mean NOT to use the Async callback to reestablish the async?

Actually, I should have written "don't call Begin*" while on a ThreadPool
Thread since it is the Begin* methods that spawn a ThreadPool Thread, not
the End* methods. The reason you shouldn't call into an asynchronous
method from an asynchronous method where both threads will use the
ThreadPool is that it can cause dead-locks because there is a limit to the
number of ThreadPool Threads provided to your application (related to the
number of physical processors). However, for a simple RPC app, especially
if there will be a limited number of client connections, it is acceptable
to call BeginAsync from the AsyncCallback.

I think that's how I had read it anyway! I do understand the danger here,
but if the re-call to Begin* is the last thing done in the callback (ie the
callback has no more oppurtunity to block) then wouldn't it be ok, even in
the worst case? I think I'll have no more than a handful of clients anyway,
but I'll think about moving to a loop I ever need to scale it up.


Your point 3 in the RPC method below suggests I should loop with a
synchronous method instead of calling BeginAsync again.

If you were to use a synchronous loop you could spawn your own Thread
using a ThreadStart object to prevent dead-locks, but there may be a
slight performance cost. I have not compared the two methods. A problem
that you must work out when using a synchronous loop is that one client
should not have to wait for another client's RPC to complete before it can
establish a connection, so some asynchronous code is still required.
Preferably, code not executing on a ThreadPool Thread.

Hmm. But if a socket has already been established (and has it's own thread
on which it is reading on), surely it wouldn't matter? Going back to my
Async model:

//somewhere else
o.BeginAsync(completeAsync, o)
....

void completeAsync(IAsyncResult ar)
{
Class o = (Class)ar.SyncState;
o.EndAsync();
//do stuff for this async cycle
//resestablish wait
o.BeginAsync(completeAsync, o)
}

This is as opposed to a sync loop:

//somewhere else

StartAThread(o.Work) //(1)
....

void Work()
{
while (true)
{
o.Begin(); // blocks
//do stuff for this cycle.
}
}

Where (1) can be replaced by your thread-kicking-off code of choice.
Presumeably for the TCPClient connecting case, "do stuff for this cycle"
means to establish a further thread to poll on read (either via async or
kicking off another thread manually). I don't think either introduce the
possibility of deadlock, although I'm now seeing the latter as being more
efficient since it doesn't create new threads. Do both these models fulfill
your condition that "one client should not have to wait for another client's
RPC to complete before it can establish a connection", though?

It seems that most Async calls (especially in streams and the like) seem to
be for a job that repeats. If this is the case, and a loop that blocks is
more efficient, what's the point of having Async calls? I mean it's not like
you'll only want to read or write to a stream once, right?

OK. I do have another question though: What happens if, while reading
bytes off of a network stream more data gets sent? Abstracting away from
the above, say you are expecting a particular message of unknown length.
How do you know when to stop reading bytes? All the examples I've seen
seem to wait till the number of bytes read<=0. Couldn't we get more than
one message accedentally in that scenario? If at all it stops?

A few things here...


That's brilliant, and exactly as I imagined it to be. In short, you have to
be able to determine when what you're receiving ends, usually using some
kind of prefix or suffix. Cool!

Shak


.



Relevant Pages

  • Re: Question abut threads
    ... protected void ConnectionHandler ... // Loop to receive all the data sent by the client. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Detecting dropped socket connections
    ... > ...in a loop, so that I only run BeginReceivewhen there is data ... > If I understand TCP/IP correctly, when the client closes the connection, ... The above method is called at the start of each async callback method, ...
    (microsoft.public.dotnet.languages.csharp)
  • (syncookckie bug?) Re: TCP zombie connections with 7-RELEASE and STABLE from 15th june
    ... The client is a telnet, which disconnects directly after connecting, ... The server however has the connection still in ESTABLISHED state. ... loop accepts the old connection again. ... The question is why accept returns me a filedescriptor for a connection ...
    (freebsd-net)
  • Detecting dropped socket connections
    ... I have a server with an open socket, ... ...in a loop, so that I only run BeginReceivewhen there is data present ... will tell me whether the client has closed the connection? ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: What happened to SqlConnection.BeginOpen?
    ... Once the pool is full, it means that there are no more connections to ... Hitchhiker's Guide to Visual Studio and SQL Server ... support Async I/O with ADO.Net. ... database connection - this means that once we need to hit the DB we're ...
    (microsoft.public.dotnet.framework.adonet)