3

我有一个 C# 程序,其中有很多(比如说大约一千个)打开的 TcpClient 对象。我想进入一种状态,等待任何这些连接发生某些事情。

我宁愿不为每个连接启动一个线程。

就像是...

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);
}

附加信息:
TcpClient 对象来自 TcpListener。
目标环境将是 MS .NET 或 Mono-on-Linux。
该协议要求在连接打开时长时间处于空闲状态。

4

1 回答 1

2

您尝试执行的操作在 Microsoft 术语中称为异步模式。总体思路是将所有 I/O 阻塞操作更改为非阻塞操作。如果这样做,应用程序通常需要与机器上的 CPU 内核一样多的系统线程。

看看 .Net 4 中的任务并行库:http: //msdn.microsoft.com/en-us/library/dd460717%28VS.100%29.aspx

它是对普通的 Begin/Callback/Context .Net 范例的非常成熟的包装器。

更新:

从连接中读取数据后,请考虑如何处理数据。在现实生活中,您可能必须回复客户端或将数据保存到文件中。在这种情况下,您将需要一些 C# 基础架构来包含/管理您的逻辑,并且仍然保留在单个线程中。TPL 免费为您提供。它唯一的缺点是它是在 .Net 4 中引入的,所以它可能还没有在 Mono 中。

要考虑的另一件事是连接的生命周期。您的连接多久打开/关闭一次,它们的寿命是多久?这很重要,因为接受和断开 TCP 连接需要与客户端交换数据包(这本质上是异步的,而且 - 恶意客户端可能根本不会返回 ACK(-nowledged)数据包)。如果您认为这方面对您的应用程序很重要,您可能需要研究如何在 .Net 中正确处理此问题。在 WinAPI 中对应的函数是 AcceptEx 和 DisconnectEx。可能它们使用 Begin/End 方法封装在 .Net 中 - 在这种情况下,您可以开始使用。否则,您可能必须为这些 WinAPI 调用创建一个包装器。

于 2011-04-04T17:14:45.823 回答