所以我一直在研究套接字编程并阅读创建高性能服务器的方法。
阅读使用AcceptAsync
的{{1}}方法以及如果连接立即可用,有时调用可以同步执行(并返回false),以及如何将套接字重新置于监听状态之后接受连接,我开始怀疑这是否真的意味着,虽然使用Socket
接受连接的套接字将异步“等待”,最终它一次只处理1个新连接,即使一次连接1000个客户端,并且取决于将客户端传递给另一个线程进行处理的速度,可能会限制性能。
这让我想知道我是否可以用这个来编写我的类,使用AcceptAsync
的单个实例用于所有连接,而不是我最初想要的对象池。
更多地考虑这个问题,我想知道在这种情况下如果在没有连接的情况下进行多次SocketAsyncEventArgs
调用会发生什么。所以我做了这个非常粗略的测试应用程序,看看会发生什么:
AcceptAsync
我使用tcp测试应用程序通过连接向应用程序发送垃圾邮件,结果显示多个class Program
{
private static Socket s;
static void Main(string[] args)
{
s = new Socket(IPAddress.Any.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
s.Bind(new IPEndPoint(IPAddress.Any, 10001));
s.Listen(10);
var e = new SocketAsyncEventArgs();
e.Completed += EOnCompleted;
s.AcceptAsync(e);
e = new SocketAsyncEventArgs();
e.Completed += EOnCompleted;
s.AcceptAsync(e);
e = new SocketAsyncEventArgs();
e.Completed += EOnCompleted;
s.AcceptAsync(e);
e = new SocketAsyncEventArgs();
e.Completed += EOnCompleted;
s.AcceptAsync(e);
while (true)
{
}
}
private static void EOnCompleted(object sender, SocketAsyncEventArgs socketAsyncEventArgs)
{
Console.WriteLine(socketAsyncEventArgs.AcceptSocket.RemoteEndPoint);
Thread.Sleep(10000);
var e = new SocketAsyncEventArgs();
e.Completed += EOnCompleted;
s.AcceptAsync(e);
}
}
调用创建了多个似乎并行执行的Accept / Complete周期。
我的问题是,这实际上有什么好处吗?这是否允许更快地处理传入连接的合法方式?有什么缺点吗?
编辑1:进一步研究这似乎技术上可能的是,如果数据始终可用于处理异步调用,它们将全部同步运行并且永远不会返回接受新连接,或者至少可能存在一个重大的延迟。
如果情况确实如此,您如何生产高性能服务器?
答案 0 :(得分:2)
通常,只需要这段代码:
while (true) {
var socket = listener.Accept();
Task.Run(async () => await RunConnectionAsync(socket));
}
此代码的用户模式部分将非常快速地运行。几乎所有时间都将花在内核上。这将很快接受连接。由于内核管理的待办事项,不会删除任何连接。
很少需要多次未完成的接受来达到您的性能目标。如果您确实需要,只需在多个线程上运行相同的代码。
SocketAsyncEventArgs
API与过时相关。基于任务的IO更加方便,只需要更多CPU密集型。
特别是,如果为每个操作创建一个新的SocketAsyncEventArgs
,您将失去该模式的所有好处。这毫无意义。
在几乎所有情况下,您都不需要异步IO来接受套接字。它执行的CPU时间更长,因此延迟时间稍长。