2

为了这个问题,我做了一个超级简化的例子:

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 才不会融化?

当给定套接字上有挂起的连接时,有没有办法只在操作系统事件上监听和唤醒?(像libuv (node.js)这样的东西,这就是我添加的原因)

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

我知道BeginAccept还有其他一堆 Async 家族,但由于他们的多线程性质,这些人是不可接受的。

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

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

4

3 回答 3

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);
}
于 2014-03-12T15:18:55.560 回答
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每个套接字一个线程并不能很好地扩展,但它会在你只是玩的时候工作得很好。

于 2014-03-12T15:18:45.037 回答
-2

循环将尽可能快地进行——这就是为什么它会占用你这么多的 CPU 周期。

尝试添加

System.Threading.Thread.Sleep(10);

在你的身体里。

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

我希望我回答了你的问题。

于 2014-07-26T18:45:47.030 回答