0

我在 C# 中使用 TcpClient 类。

每次有新的 tcp 连接请求时,通常的做法是创建一个新线程来处理它。并且主线程应该可以随时终止这些处理程序线程。

我对每个处理程序线程的解决方案如下:

1 Check NetworkStream's DataAvailable method
    1.1 If new data available then read and process new data
    1.2 If end of stream then self terminate
2 Check for terminate signal from main thread
    2.1 If terminate signal activated then self terminate
3 Goto 1.

这种轮询方法的问题在于,所有这些处理程序线程都将占用大量的处理器资源,尤其是在这些线程数量巨大的情况下。这使得它非常低效。

有没有更好的方法来做到这一点?

4

4 回答 4

2

请参阅异步服务器套接字示例以了解如何以“.NET 方式”执行此操作,而无需为每个请求创建新线程。

于 2009-12-08T02:58:34.620 回答
1

信不信由你,1000 滴答睡眠真的会让事情顺利进行。

private readonly Queue<Socket> sockets = new Queue<Socket>();
private readonly object locker = new object();
private readonly TimeSpan sleepTimeSpan = new TimeSpan(1000);
private volatile Boolean terminate;

private void HandleRequests() 
{
    Socket socket = null;

    while (!terminate)
    {
        lock (locker)
        {
            socket = null;
            if (sockets.Count > 0)
            {
                socket = sockets.Dequeue();
            }
        }

        if (socket != null)
        {
            // process
        }

        Thread.Sleep(sleepTimeSpan);
    }   
}
于 2009-12-08T03:07:51.720 回答
0

我记得曾在类似的 Windows 服务上工作过。它是一个 NTRIP 服务器,可以接收大约 1000 个 TCP 连接并将数据路由到 NTRIP Caster。

如果您为此应用程序有一个专用服务器,那么除非您向每个线程添加更多代码(文件 IO、数据库等 - 尽管在我的情况下我也有数据库处理来记录每个连接的输入/输出),否则它不会成为问题.

需要注意的事项:

  1. 线程达到 600 左右时的带宽。当 TCP 缓冲区窗口由于某种原因被阻塞或可用带宽不足时,您将开始看到断开连接
  2. 您运行此应用程序的操作系统可能有一些限制,这可能会导致断开连接

以上内容可能不适用于您的情况,但我只是希望将其放在这里,因为我当时在开发过程中遇到过。

于 2009-12-08T02:49:21.297 回答
0

没错,您不希望所有线程都“忙于等待”(即一遍又一遍地运行一个小循环)。您要么希望它们阻塞,要么希望使用异步 I/O。

正如 John Saunders 所提到的,异步 I/O 是执行此操作的“正确方法”,因为它可以扩展到数百个连接。基本上,您调用 BeginRead() 并将其传递给回调函数。BeginRead() 立即返回,当数据到达时,在线程池中的一个线程上调用回调函数。回调函数处理数据,再次调用 BeginRead(),然后返回,将线程释放回池中。

但是,如果您一次只打开少数几个连接,则为每个连接创建一个线程是非常好的。不要在循环中检查 DataAvailable 属性,而是继续调用 Read()。线程将阻塞,不消耗 CPU,直到有数据可供读取。如果连接丢失,或者您从另一个线程将其关闭,则 Read() 调用将引发异常,您可以通过终止阅读器线程来处理该异常。

于 2009-12-08T03:02:40.783 回答