Question

I am using the TcpClient class in C#.

Each time there is a new tcp connection request, the usual practice is to create a new thread to handle it. And it should be possible for the main thread to terminate these handler threads anytime.

My solution for each of these handler thread is as follows:

1 Check NetworkStream's DataAvailable method
    1.1 If new data available then read and process new data
    1.2 If end of stream then self terminate
2 Check for terminate signal from main thread
    2.1 If terminate signal activated then self terminate
3 Goto 1.

The problem with this polling approach is that all of these handler threads will be taking up significant processor resources and especially so if there is a huge number of these threads. This makes it highly inefficient.

Is there a better way of doing this?

Was it helpful?

Solution

See Asynchronous Server Socket Example to learn how to do this the ".NET way", without creating new threads for each request.

OTHER TIPS

Believe it or not that 1000 tick sleep will really keep things running smooth.

private readonly Queue<Socket> sockets = new Queue<Socket>();
private readonly object locker = new object();
private readonly TimeSpan sleepTimeSpan = new TimeSpan(1000);
private volatile Boolean terminate;

private void HandleRequests() 
{
    Socket socket = null;

    while (!terminate)
    {
        lock (locker)
        {
            socket = null;
            if (sockets.Count > 0)
            {
                socket = sockets.Dequeue();
            }
        }

        if (socket != null)
        {
            // process
        }

        Thread.Sleep(sleepTimeSpan);
    }   
}

I remember working on a similar kind of Windows Service. It was a NTRIP Server that can take around 1000 TCP connections and route the data to a NTRIP Caster.

If you have a dedicated server for this application then it will not be a problem unless you add more code to each thread (File IO, Database etc - although in my case I also had Database processing to log the in/out for each connection).

The things to watch out for:

  1. Bandwidth when the threads goes up to 600 or so. You will start seeing disconnections when the TCP Buffer window is choked for some reason or the available bandwidth falls short
  2. The operating system on which you are running this application might have some restrictions, which can cause disconnections

The above might not be applicable in your case but I just wanted it put it here because I faced then during development.

You're right that you do not want all of your threads "busy waiting" (i.e. running a small loop over and over). You either want them blocking, or you want to use asynchronous I/O.

As John Saunders mentioned, asynchronous I/O is the "right way" to do this, since it can scale up to hundreds of connections. Basically, you call BeginRead() and pass it a callback function. BeginRead() returns immediately, and when data arrives, the callback function is invoked on a thread from the thread pool. The callback function processes the data, calls BeginRead() again, and then returns, which releases the thread back into the pool.

However, if you'll only be holding a handful of connections open at a time, it's perfectly fine to create a thread for each connection. Instead of checking the DataAvailable property in a loop, go ahead and call Read(). The thread will block, consuming no CPU, until data is available to read. If the connection is lost, or you close it from another thread, the Read() call will throw an exception, which you can handle by terminating your reader thread.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top