套接字侦听器多个同时接受异步调用

时间:2016-04-07 21:26:46

标签: c# sockets network-programming

所以我一直在研究套接字编程并阅读创建高性能服务器的方法。

阅读使用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:进一步研究这似乎技术上可能的是,如果数据始终可用于处理异步调用,它们将全部同步运行并且永远不会返回接受新连接,或者至少可能存在一个重大的延迟。

如果情况确实如此,您如何生产高性能服务器?

1 个答案:

答案 0 :(得分:2)

通常,只需要这段代码:

while (true) {
 var socket = listener.Accept();
 Task.Run(async () => await RunConnectionAsync(socket));
}

此代码的用户模式部分将非常快速地运行。几乎所有时间都将花在内核上。这将很快接受连接。由于内核管理的待办事项,不会删除任何连接。

很少需要多次未完成的接受来达到您的性能目标。如果您确实需要,只需在多个线程上运行相同的代码。

SocketAsyncEventArgs API与过时相关。基于任务的IO更加方便,只需要更多CPU密集型。

特别是,如果为每个操作创建一个新的SocketAsyncEventArgs,您将失去该模式的所有好处。这毫无意义。

在几乎所有情况下,您都不需要异步IO来接受套接字。它执行的CPU时间更长,因此延迟时间稍长。