You probably need to use a queue. Here is a sketch of a possible solution on the server side:
class Program
{
Queue<Connection> queue = new Queue<Connection>();
TcpListener listener;
ManualResetEvent reset = new ManualResetEvent(true);
static void Main(string[] args)
{
new Program().Start();
}
void Start()
{
new Thread(new ThreadStart(HandleConnection)).Start();
while (true)
{
while (queue.Any())
{
var connection = queue.Dequeue();
connection.DoStuff();
if(!connection.Finished)
queue.Enqueue(connection);
}
reset.WaitOne();
}
}
static readonly byte[] CONNECTION_REFUSED = Encoding.ASCII.GetBytes("Cannot accept a connection right now.");
static readonly int CONNECTION_REFUSED_LENGTH = CONNECTION_REFUSED.Length;
void HandleConnection()
{
listener.Start();
while (true)
{
var client = listener.AcceptTcpClient();
if (queue.Count <= 10)
{
queue.Enqueue(new Connection(client));
reset.Set();
}
else
{
client.GetStream().Write(CONNECTION_REFUSED, 0, CONNECTION_REFUSED_LENGTH);
client.Close();
}
}
}
}
public sealed class Connection
{
readonly TcpClient client;
readonly Stopwatch stopwatch = new Stopwatch();
public Connection(TcpClient client)
{
this.client = client;
stopwatch.Start();
}
public void DoStuff()
{
}
public void Abort()
{
//You can write out an abort message to the client if you like.
client.Close();
completed = true;
}
bool completed;
public bool Finished
{
get
{
return stopwatch.ElapsedMilliseconds > 30 * 1000 || completed;
}
}
}
The basic idea is to use one thread to add incoming connections to a queue ,then use another thread to iterate through the queue to do stuff with each connection. A connection is removed from the queue (or rather not re-enqueued) when it is Finished
.
A robust solution will probably require using either the lock
statement or the ConcurrentQueue
class. In my sketch, I used the blocking methods on the TCPClient
class for the sake off brevity, but, of course you will want to use the non-blocking ones.