Async socks in a separate thread

  • Thread starter Thread starter MuZZy
  • Start date Start date
M

MuZZy

Hi,

Could someone pls help me here:

If i use async sockets in the separate thread like this:

void ThreadFunction()
{
.....
1. MySocket.BeginAccept(AsyncCallBack(OnConnectRequest), MySocket);
2. ??????????
}

What do i do after line 1?
Do i put an endless loop in order to keep the thread alive?
And where do i put try{} catch{} to catch ThreadAbortException thrown into the thread when i call Abort on the thread?

Thank you,
Andrey
 
MuZZy,

-- FYI Managed Threading Best Practices does not recommend using Abort to
terminate a thread. Check item #1 in "General Recommendations" at this link:

http://msdn.microsoft.com/library/d...e/html/cpconmanagedthreadingbestpractices.asp

It's better to use your own event and/or boolean flag to signal that a
thread should stop processing.

-- I found the async socket documentation to be horrible... I burned up an
MSDN helpdesk call and got the following advice:

1) Do NOT try to use the manual wait handle returned with some async socket
APIs; it is not predictable. Declare and use your own events instead.

2) Your main listening loop should open the listener socket, issue
BeginAccept(), and then sleep until a connect attempt arrives or until the
program is stopped {this implies that you'll be waiting on 2 events}. When a
connection has been accepted by the callback handler loop around and issue
BeginAccept again.

Assuming that you have declared an event to signal program stop and an event
to signal an accepted connection, psuedo code for main listening loop looks
like this:

using (Socket listener = new Socket(...))
{
listener.Bind(...);
listener.Listen(...);

bool running = true;
while (running)
{
acceptEvent.Reset();
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
switch (WaitHandle.WaitAny(acceptEvent, stopEvent))
{
case 0:
// acceptEvent - client connected, loop around again
break;
default:
// stopEvent or wait error - fall out of loop
running = false;
break;
}
}
}

3) When a client attempts to connect the accept callback handler should
issue EndAccept, signal the main thread that it has accepted a connection,
and then hand the accepted client off to another thread. The accept handler
MUST NOT process the client socket, it must EndAccept and return ASAP.

Assuming the "acceptEvent" from above, here is a working callback handler
that accepts a client connection, queues the client to the thread pool for
further processing, then signals the main loop that a client has been
accepted:

void AcceptCallback(IAsyncResult ar)
{
try
{
Socket socket = ((Socket)ar.AsyncState).EndAccept(ar);
ThreadPool.QueueUserWorkItem(new WaitCallback(SocketMain), socket);
}
catch (Exception ex)
{
trace.Exception(ex);
}
finally
{
acceptEvent.Set();
}
}

4) The ThreadPool handler "SocketMain" receives a connected socket and it
can do whatever it wishes to do with the client:

void SocketMain(object o)
{
using (Socket socket = (Socket)o)
{
... Do whatever ...
}
}

--Richard
 
Sample snippet:
AsyncCallback OnConnectRequest;

void OnConnectRequest(IAsyncResult ar)
{

// you have a connection, now start to receive---
try
{
Socket s = ar.AsyncState as Socket;
Socket s2 = s.EndAccept(ar);
// Keep the "Accept" process in motion
s.BeginAccept(acceptCallback, s);
// Create a state object for client
StateObject state = new StateObject();
state.WorkerSocket = s2;
// Start an async receive
state.WorkerSocket.BeginReceive(state.Bytes, 0,
state.Bytes.Length, 0, receiveCallback, state);
}
catch(SocketException e)
{
Debug.WriteLine(e.Message);
Console.WriteLine( "SocketException:"+ e.Message);
}
return; // Return the thread to the pool
}

Note that BeginAccept is called from within the callback method.

There are lots of different ways to do this, and it can be pretty confusing.
Some pretty good sample code to get you started at MSDN online.
Just look up "Asynchronous sockets".
--Peter
 
Peter said:
Sample snippet:
AsyncCallback OnConnectRequest;

void OnConnectRequest(IAsyncResult ar)
{

// you have a connection, now start to receive---
try
{
Socket s = ar.AsyncState as Socket;
Socket s2 = s.EndAccept(ar);
// Keep the "Accept" process in motion
s.BeginAccept(acceptCallback, s);
// Create a state object for client
StateObject state = new StateObject();
state.WorkerSocket = s2;
// Start an async receive
state.WorkerSocket.BeginReceive(state.Bytes, 0,
state.Bytes.Length, 0, receiveCallback, state);
}
catch(SocketException e)
{
Debug.WriteLine(e.Message);
Console.WriteLine( "SocketException:"+ e.Message);
}
return; // Return the thread to the pool
}

Note that BeginAccept is called from within the callback method.

There are lots of different ways to do this, and it can be pretty confusing.
Some pretty good sample code to get you started at MSDN online.
Just look up "Asynchronous sockets".
--Peter

Thank you for the reply!
But thing is that i already have what you mentioned above,
i just need to know how to keep the thread function from returning
after i've initiated BeginAccept(...).

Thank you,
Andrey
 
Or spawn a listener thread and let that block.
What do you mean here?

Never mind blocking. This is how you do it.

This code is excerpted from a custom control I wrote for an embedded
webserver. I use it to fulfil requests for addition resources like CSS or
images when I use an embedded webserver to render HTML. You can make it pick
a random port, and the widget exposes a LocalBaseUrl property that tells
your app the base URL for connecting to itself. That's what baseURL is
about.

Sockets aren't that hard but it takes a mind that's twisted in a special
way.

THIS CODE IS COPYRIGHT TO ME AND ANYONE PLANNING ON USING IT IN A
COMMERCIAL APPLICATION CAN JOLLY WELL PUBLICLY CREDIT ME.

The next Indian contractor to send a peremptory "UGENT: PLS HELP" message to
my private email address will receive pictures of dead cows in his work
inbox unless the request is accompanied by an offer to pay for my time and
trouble.


....
private TcpListener tcpListener;
private bool useRandomPort = true;
private int tcpListenerPort = 8080;
private bool shouldListen = false;
private Thread ListenerThread;
private string baseURL;

....
public void Start() {
if (useRandomPort)
tcpListenerPort = (new Random()).Next(16384,65535);
baseURL = "http://localhost:" + tcpListenerPort + "/";
tcpListener = new TcpListener(IPAddress.Loopback,tcpListenerPort);
if ((VirtualRoots.Count>0) && (null==filesys))
filesys = new WebResourceProviderFileSystem();
shouldListen = true;
tcpListener.Start();
ListenerThread = new Thread(new ThreadStart(Listen));
ListenerThread.Priority = ThreadPriority.BelowNormal;
ListenerThread.Name = string.Format("{0} HTTP
Listener",this.GetType().ToString());
ListenerThread.Start();
}
public void Stop() {
shouldListen = false;
}
....
private void Listen(){
while (shouldListen) {
if (tcpListener.Pending()){
Socket socket = tcpListener.AcceptSocket();
socket.Blocking = false;
//Some applications disconnect immediately when just checking
//the continued presence of this app. These produce SelectError.
if (!socket.Poll(5000,SelectMode.SelectError)) {
//spawn another thread to handle this request
HttpRequestHandler handler = new
HttpRequestHandler(this,socket);
Thread newThread = new Thread(new ThreadStart(handler.Exec));
newThread.Name = string.Format("{0} request
handler",this.GetType().ToString());
newThread.Start();
}
} else
Thread.Sleep(200);
}
}
 
The next Indian contractor to send a peremptory "UGENT: PLS HELP" message
to my private email address will receive pictures of dead cows in his work
That comment was in poor taste. I hope you realize that.

--
Regards,
Alvin Bruney

[Shameless Author plug]
The Microsoft Office Web Components Black Book with .NET
Now Available @ http://tinyurl.com/27cok
 
So are the peremptory demands to do unpaid work that they get paid for.

Alvin Bruney said:
The next Indian contractor to send a peremptory "UGENT: PLS HELP" message
to my private email address will receive pictures of dead cows in his
work
That comment was in poor taste. I hope you realize that.

--
Regards,
Alvin Bruney

[Shameless Author plug]
The Microsoft Office Web Components Black Book with .NET
Now Available @ http://tinyurl.com/27cok
----------------------------------------------------------


Peter Wone said:
Never mind blocking. This is how you do it.

This code is excerpted from a custom control I wrote for an embedded
webserver. I use it to fulfil requests for addition resources like CSS or
images when I use an embedded webserver to render HTML. You can make it
pick a random port, and the widget exposes a LocalBaseUrl property that
tells your app the base URL for connecting to itself. That's what baseURL
is about.

Sockets aren't that hard but it takes a mind that's twisted in a special
way.

THIS CODE IS COPYRIGHT TO ME AND ANYONE PLANNING ON USING IT IN A
COMMERCIAL APPLICATION CAN JOLLY WELL PUBLICLY CREDIT ME.

The next Indian contractor to send a peremptory "UGENT: PLS HELP" message
to my private email address will receive pictures of dead cows in his
work inbox unless the request is accompanied by an offer to pay for my
time and trouble.


...
private TcpListener tcpListener;
private bool useRandomPort = true;
private int tcpListenerPort = 8080;
private bool shouldListen = false;
private Thread ListenerThread;
private string baseURL;

...
public void Start() {
if (useRandomPort)
tcpListenerPort = (new Random()).Next(16384,65535);
baseURL = "http://localhost:" + tcpListenerPort + "/";
tcpListener = new TcpListener(IPAddress.Loopback,tcpListenerPort);
if ((VirtualRoots.Count>0) && (null==filesys))
filesys = new WebResourceProviderFileSystem();
shouldListen = true;
tcpListener.Start();
ListenerThread = new Thread(new ThreadStart(Listen));
ListenerThread.Priority = ThreadPriority.BelowNormal;
ListenerThread.Name = string.Format("{0} HTTP
Listener",this.GetType().ToString());
ListenerThread.Start();
}
public void Stop() {
shouldListen = false;
}
...
private void Listen(){
while (shouldListen) {
if (tcpListener.Pending()){
Socket socket = tcpListener.AcceptSocket();
socket.Blocking = false;
//Some applications disconnect immediately when just checking
//the continued presence of this app. These produce SelectError.
if (!socket.Poll(5000,SelectMode.SelectError)) {
//spawn another thread to handle this request
HttpRequestHandler handler = new
HttpRequestHandler(this,socket);
Thread newThread = new Thread(new ThreadStart(handler.Exec));
newThread.Name = string.Format("{0} request
handler",this.GetType().ToString());
newThread.Start();
}
} else
Thread.Sleep(200);
}
}
 
Back
Top