如何通过 .NET 中的线程传播 tcplistener 传入连接?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/62449/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 09:51:03  来源:igfitidea点击:

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

.netmultithreadingtcplistener

提问by Jorrit Reedijk

When using the Net.Sockets.TcpListener, what is the best way to handle incoming connections (.AcceptSocket) in seperate threads?

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

The idea is to start a new thread when a new incoming connection is accepted, while the tcplistener then stays available for further incoming connections (and for every new incoming connection a new thread is created). All communication and termination with the client that originated the connection will be handled in the thread.

这个想法是在接受新的传入连接时启动一个新线程,而 tcplistener 然后保持可用于进一步传入连接(并且为每个新传入连接创建一个新线程)。与发起连接的客户端的所有通信和终止都将在线程中处理。

Example C# of VB.NET code is appreciated.

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

采纳答案by Anton

The code that I've been using looks like this:

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

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

回答by Mike Dimmick

I believe you do it in the same way as any other asynchronous operation in .NET: you call the BeginXxx version of the method, in this case BeginAcceptSocket. Your callback will execute on the thread pool.

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

Pooled threads generally scale much better than thread-per-connection: once you get over a few tens of connections, the system works much harder in switching between threads than on getting actual work done. In addition, each thread has its own stack which is typically 1MB in size (though it depends on link flags) which has to be found in the 2GB virtual address space (on 32-bit systems); in practice this limits you to fewer than 1000 threads.

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

I'm not sure whether .NET's threadpool currently uses it, but Windows has a kernel object called the I/O Completion Port which assists in scalable I/O. You can associate threads with this object, and I/O requests (including accepting incoming connections) can be associated with it. When an I/O completes (e.g. a connection arrives) Windows will release a waiting thread, but only if the number of currently runnable threads (not blocked for some other reason) is less than the configured scalability limit for the completion port. Typically you'd set this to a small multiple of the number of cores.

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

回答by Dror Helper

I'd like to suggest a diffrent approach: My suggestion uses only two threads. * one thread checks for incomming connections. * When a new connection opened this info is written to a shared data structure that holds all of the current open connections. * The 2nd thread enumerate that data structure and for each open connection recieve data sent and send replys.

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

This solution is more scaleable thread-wise and if implemented currectly should have better performance then opening a new thread per opened connection.

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

回答by x0n

There's a great example in the O'Reilly C# 3.0 Cookbook. You can download the accompanying source from http://examples.oreilly.com/9780596516109/CSharp3_0CookbookCodeRTM.zip

O'Reilly C# 3.0 Cookbook 中有一个很好的例子。您可以从以下位置下载随附的源代码http://examples.oreilly.com/9780596516109/CSharp3_0CookbookCodeRTM.zip

回答by Paul van Brenk

I would use a threadpool, this way you won't have to start a new thread every time (since this is kinda expensive). I would also not wait indefinetely for furhter connections, since clients may not close their connections. How do you plan to route the client to the same thread each time?

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

Sorry, don't have sample.

对不起,没有样品。