views:

4486

answers:

5

When using the Net.Sockets.TcpListener, what is the best way to handle incoming connections (.AcceptSocket) in seperate threads?

The idea is to start a new thread when a new incoming connection is accepted, while the tcplistener then stays available for further incoming connections (and for every new incoming connection a new thread is created). All communication and termination with the client that originated the connection will be handled in the thread.

Example C# of VB.NET code is appreciated. Thanks in advance.

A: 

I would use a threadpool, this way you won't have to start a new thread every time (since this is kinda expensive). I would also not wait indefinetely for furhter connections, since clients may not close their connections. How do you plan to route the client to the same thread each time?

Sorry, don't have sample.

pb
A: 

There's a great example in the O'Reilly C# 3.0 Cookbook. You can download the accompanying source from [http://examples.oreilly.com/9780596516109/CSharp3_0CookbookCodeRTM.zip][1]

x0n
+1  A: 

I believe you do it in the same way as any other asynchronous operation in .NET: you call the BeginXxx version of the method, in this case BeginAcceptSocket. Your callback will execute on the thread pool.

Pooled threads generally scale much better than thread-per-connection: once you get over a few tens of connections, the system works much harder in switching between threads than on getting actual work done. In addition, each thread has its own stack which is typically 1MB in size (though it depends on link flags) which has to be found in the 2GB virtual address space (on 32-bit systems); in practice this limits you to fewer than 1000 threads.

I'm not sure whether .NET's threadpool currently uses it, but Windows has a kernel object called the I/O Completion Port which assists in scalable I/O. You can associate threads with this object, and I/O requests (including accepting incoming connections) can be associated with it. When an I/O completes (e.g. a connection arrives) Windows will release a waiting thread, but only if the number of currently runnable threads (not blocked for some other reason) is less than the configured scalability limit for the completion port. Typically you'd set this to a small multiple of the number of cores.

Mike Dimmick
+1  A: 

I'd like to suggest a diffrent approach: My suggestion uses only two threads. * one thread checks for incomming connections. * When a new connection opened this info is written to a shared data structure that holds all of the current open connections. * The 2nd thread enumerate that data structure and for each open connection recieve data sent and send replys.

This solution is more scaleable thread-wise and if implemented currectly should have better performance then opening a new thread per opened connection.

Dror Helper
This I will remember, although I would really like to answer each incoming connection immediately. Thanks for the suggestion.
Jorrit Reedijk
+6  A: 

The code that I've been using looks like this:

class Server()
{
  private AutoResetEvent connectionWaitHandle = new AutoResetEvent(false);

  public void Start()
  {
    TcpListener listener = new TcpListener(IPAddress.Any, 5555);
    listener.Start();

    while(true)
    {
      IAsyncResult result =  tcpListener.BeginAcceptTcpClient(HandleAsyncConnection, tcpListener);
      connectionWaitHandle.WaitOne(); //Wait until a client has begun handling an event
    }
  }


  private void HandleAsyncConnection(IAsyncResult result)
  {
    TcpListener listener = (TcpListener)result.AsyncState;
    TcpClient client = listener.EndAcceptTcpClient(result);
    connectionWaitHandle.Set(); //Inform the main thread this connection is now handled

    //... Use your TcpClient here

    client.Close();
  }
}
Anton
Thanks for the sourcecode, I will be coding it like this. New threads may be expensive, but since I have not scale beyond 5 or 6 concurrent incoming connections, this will be fine for now.
Jorrit Reedijk
Think listener and tcpListener got confused in example, otherwise good code. Found this: http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.beginaccepttcpclient.aspx based on what I leant here.
Justin Wignall