关于多线程:如何在.NET中的线程上分散tcplistener的传入连接?

关于多线程:如何在.NET中的线程上分散tcplistener的传入连接?

How to spread tcplistener incoming connections over threads in .NET?

使用Net.Sockets.TcpListener时,在单独的线程中处理传入连接(.AcceptSocket)的最佳方法是什么?

这个想法是当新的传入连接被接受时启动一个新线程,而tcplistener则可用于其他传入连接(并为每个新的传入连接创建一个新线程)。与发起连接的客户端的所有通信和终止将在线程中处理。

赞赏VB.NET代码的示例C#。


我一直在使用的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Server
{
  private AutoResetEvent connectionWaitHandle = new AutoResetEvent(false);

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

    while(true)
    {
      IAsyncResult result =  listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
      connectionWaitHandle.WaitOne(); // Wait until a client has begun handling an event
      connectionWaitHandle.Reset(); // Reset wait handle or the loop goes as fast as it can (after first request)
    }
  }


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

我相信您可以通过与.NET中任何其他异步操作相同的方式来执行此操作:您调用该方法的BeginXxx版本,在本例中为BeginAcceptSocket。您的回调将在线程池上执行。

池化线程的可伸缩性通常比每个连接的线程好得多:一旦获得几十个连接,系统在线程之间进行切换的工作要比完成实际工作困难得多。此外,每个线程都有自己的堆栈,堆栈大小通常为1MB(尽管取决于链接标志),必须在2GB虚拟地址空间(在32位系统上)中找到该堆栈;实际上,这会将您限制为少于1000个线程。

我不确定.NET \\的线程池当前是否使用它,但是Windows有一个称为I / O完成端口的内核对象,该对象有助于可伸缩的I / O。您可以将线程与此对象关联,并且I / O请求(包括接受传入的连接)可以与其关联。当I / O完成(例如连接到达)时,Windows将释放等待线程,但前提是当前可运行线程的数量(由于其他原因未被阻止)小于完成端口配置的可扩展性限制。通常,您会将其设置为内核数的一小部分。


我想提出一种不同的方法:
我的建议仅使用两个线程。
*一个线程检查传入的连接。
*当打开新连接时,此信息将写入包含所有当前打开的连接的共享数据结构。
*第二个线程枚举该数据结构,并为每个打开的连接接收已发送的数据并发送答复。

此解决方案在线程方面更具可伸缩性,如果正确实施,则应具有更好的性能,然后在每个打开的连接中打开一个新线程。


O \\'Reilly C#3.0 Cookbook中有一个很好的例子。您可以从http://examples.oreilly.com/9780596516109/CSharp3_0CookbookCodeRTM.zip

下载随附的源代码


我会使用线程池,这样您就不必每次都启动一个新线程(因为这有点贵)。我也不会无限期地等待进一步的连接,因为客户端可能不会关闭其连接。您打算如何计划每次将客户端路由到同一线程?

对不起,没有样品。


推荐阅读