出于这个问题的目的,我做了一个超简化的例子:
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)这样的东西,这就是我添加single-threaded)
的原因我的实际实现是针对一个相当基本的Reactor事件循环,但是,我不知道如何用C#监听OS事件(如果有可能的话)。
我知道BeginAccept
和另一堆Async系列,但由于它们的多线程特性,这些人不可加入。
另外,我知道我可以在循环中简单地Thread.Sleep
,但我正在寻找基于事件的行为。
P.S。我正在使用Mono,目标是Linux可执行文件。
答案 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周期使用率大大降低,并防止主线程阻塞。
我希望我回答你的问题。