3

I've got a C# program with lots (let's say around a thousand) opened TcpClient objects. I want to enter a state which will wait for something to happen for any of those connections.

I would rather not launch a thread for each connection.

Something like...

while (keepRunning)
{
     // Wait for any one connection to receive something.
     TcpClient active = WaitAnyTcpClient(collectionOfOpenTcpClients);

     // One selected connection has incomming traffic. Deal with it.
     // (If other connections have traffic during this function, the OS
     // will have to buffer the data until the loop goes round again.)
     DealWithConnection(active);
}

Additional info:
The TcpClient objects come from a TcpListener.
The target environment will be MS .NET or Mono-on-Linux.
The protocol calls for long periods of idleness while the connection is open.

billpg
  • 3,195
  • 3
  • 30
  • 57
  • 1
    In Unix world you would use `select` syscall to do this. I'm sure there's some analog in Windows. – Victor Sorokin Apr 04 '11 at 17:02
  • 1
    Your assumption of a "thread for each connection" is flawed. Thread pools coupled with APM methods are the way to go with this kind of problem. Just a few threads can service many many clients. This answer I gave should prove informative: http://stackoverflow.com/questions/3153959/how-does-a-full-featured-long-polling-server-work-abstractly/3154115#3154115 – spender Apr 04 '11 at 17:11
  • @spender - You suggest I BeginRead all ~1000 TcpClients and deal with any traffic in the call-back? If you want to write that into an answer I'll accept it. – billpg Apr 04 '11 at 17:24

1 Answers1

2

What you're trying to do is called an Async Pattern in Microsoft terminology. The overall idea is to change all I/O blocking operations to non-blocking. If this is done, the application usually needs as many system threads as there are CPU cores at the machine.

Take a look at Task Parallel Library in .Net 4: http://msdn.microsoft.com/en-us/library/dd460717%28VS.100%29.aspx

It's a pretty mature wrapper over the plain old Begin/Callback/Context .Net paradigm.

Update:

Think about what to you will do with the data after you read from the connection. In real life you probably have to reply to the client or save the data to a file. In this case you will need some C# infrastructure to contain/manage your logic and still stay within a single thread. TPL provides it to you for free. Its only drawback is that it was introduced in .Net 4, so probably it's not in Mono yet.

Another thing to consider is connection's lifetime. How often your connections are opened/closed and how long do they live? This is important because accepting and disconnecting a TCP connection requires packet exchange with the client (which is asynchronous by nature, and moreover - a malicious client may not return ACK(-nowledged) packets at all). If you think this aspect is significant for your app, you may want to research how to handle this properly in .Net. In WinAPI the corresponding functions are AcceptEx and DisconnectEx. Probably they are wrapped in .Net with Begin/End methods - in this case you're good to go. Otherwise you'll probably have to create a wrapper over these WinAPI calls.

Krit
  • 548
  • 3
  • 9