代码之家  ›  专栏  ›  技术社区  ›  pgras

如何在.NET中的线程上分布tcplistener传入连接?

  •  15
  • pgras  · 技术社区  · 16 年前

    使用net.sockets.tcplistener时,在单独的线程中处理传入连接(.acceptsocket)的最佳方法是什么?

    其思想是在接受新的传入连接时启动一个新的线程,而tcplistener则保持对进一步的传入连接可用(对于每个新的传入连接,都会创建一个新的线程)。与发起连接的客户机的所有通信和终止都将在线程中处理。

    欢迎使用vb.net代码的示例c。

    5 回复  |  直到 9 年前
        1
  •  14
  •   community wiki 5 revs, 4 users 93% Anton    12 年前

    我一直使用的代码如下:

    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();
      }
    }
    
        2
  •  3
  •   Mike Dimmick    16 年前

    我相信您这样做的方式与.NET中的任何其他异步操作相同:您调用方法的BeginXXX版本,在本例中是BeginAcceptSocket。您的回调将在线程池上执行。

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

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

        3
  •  2
  •   Dror Helper    16 年前

    我建议采用不同的方法: 我的建议只有两条线索。 *一个螺纹检查进线连接。 *当新连接打开时,此信息将写入保存所有当前打开连接的共享数据结构。 *第二个线程枚举该数据结构,并为每个打开的连接接收发送和发送回复的数据。

    此解决方案更易于扩展线程,如果当前实现,则应该具有更好的性能,然后为每个打开的连接打开一个新线程。

        4
  •  1
  •   Ian Boyd    13 年前

    在O'Reilly C 3.0食谱中有一个很好的例子。您可以从下载随附的源 http://examples.oreilly.com/9780596516109/CSharp3_0CookbookCodeRTM.zip

        5
  •  0
  •   Paul van Brenk    16 年前

    我会使用线程池,这样你就不必每次都启动一个新线程(因为这有点昂贵)。我也不会无限地等待更频繁的连接,因为客户机可能不会关闭他们的连接。您计划如何每次将客户机路由到同一线程?

    对不起,没有样品。