TcpListener服务器循环到空闲,直到有挂起的连接

时间:2014-03-12 15:07:27

标签: c# events mono tcplistener single-threaded

出于这个问题的目的,我做了一个超简化的例子:

using System;
using System.Net;
using System.Net.Sockets;

namespace Loop
{
    class Program
    {
        public static void Main (string[] args)
        {
            TcpListener server = new TcpListener(IPAddress.Any, 1337);

            server.Start();

            Console.WriteLine("Starting listener on {0}:{1}", IPAddress.Any, 1337);

            while (true)
            {
                if (server.Pending())
                {
                    Console.WriteLine("Activity...");

                    Socket client = server.AcceptSocket();

                    IPEndPoint clientAddress = (IPEndPoint) client.RemoteEndPoint;

                    Console.WriteLine("Accepted client: {0}:{1}", clientAddress.Address, clientAddress.Port);

                    client.Close();

                    Console.WriteLine("Closed connection to: {0}:{1}", clientAddress.Address, clientAddress.Port);
                }
                else
                {
                    // Currently takes 100% of my CPU (well, actually Core - 25%, but you get the idea).
                    // How do I idle (CPU @ 0%) the loop until pending connection?
                }
            }
        }
    }
}

评论已经包含了这个问题,但是,如果在实际挂起的连接之前我如何空闲循环,以便我的CPU没有融化?

当给定套接字上存在挂起连接时,是否有办法仅在OS事件上侦听和唤醒? (像libuv (node.js)这样的东西,这就是我添加

的原因

我的实际实现是针对一个相当基本的Reactor事件循环,但是,我不知道如何用C#监听OS事件(如果有可能的话)。

我知道BeginAccept和另一堆Async系列,但由于它们的多线程特性,这些人不可加入。

另外,我知道我可以在循环中简单地Thread.Sleep,但我正在寻找基于事件的行为。

P.S。我正在使用Mono,目标是Linux可执行文件。

3 个答案:

答案 0 :(得分:3)

我建议您只删除对挂起连接的检查,并让主线程块(AcceptSocket是阻塞方法)直到接受连接:

while (true)
{
    Console.WriteLine("Waiting for client to connect...");

    Socket client = server.AcceptSocket(); // This is a blocking call...

    Console.WriteLine("Client connected...");

    IPEndPoint clientAddress = (IPEndPoint) client.RemoteEndPoint;

    Console.WriteLine("Accepted client: {0}:{1}", clientAddress.Address, clientAddress.Port);

    client.Close();

    Console.WriteLine("Closed connection to: {0}:{1}", clientAddress.Address, clientAddress.Port);
}

答案 1 :(得分:2)

您正在使用可用的机制(Pending避免等待,然后因为您想等待而遇到问题:

        while (true)
        {
                Socket client = server.AcceptSocket();

                Console.WriteLine("Activity...");

                IPEndPoint clientAddress = (IPEndPoint) client.RemoteEndPoint;

                Console.WriteLine("Accepted client: {0}:{1}", clientAddress.Address, clientAddress.Port);

                client.Close();

                Console.WriteLine("Closed connection to: {0}:{1}", clientAddress.Address, clientAddress.Port);
        }

AcceptSocket阻止,直到它获得连接。

通常,在获得连接之后,您将打开的套接字移到其他地方(专用线程 1 或线程池或其他东西)然后再回到再次调用AcceptSocket,以便一次可以连接多个客户端。

1 每个插槽一个线程实际上并不能很好地扩展,但是当你只是玩游戏时它会运行得很好。

答案 2 :(得分:-2)

循环将尽可能快 - 这就是为什么它占用了这么多的CPU周期。

尝试添加

System.Threading.Thread.Sleep(10);

在你的身体里。

以上将解决高CPU负载,但是当您调用Sleep()方法时,它不会解决主线程上发生的阻塞。我个人建议在新的(IsBackground = true)线程下运行你的服务器循环。这将导致CPU周期使用率大大降低,并防止主线程阻塞。

我希望我回答你的问题。