使用System.Net.Sockets.Socket.AcceptAsync模型时堆栈溢出

Mic*_*ray 13 c# sockets asynchronous

对于C#和.NET的System.Net.Sockets.Socket.AcceptAsync方法,需要处理返回值"false"以便处理SocketAsyncEventArgs来自同步处理的连接的立即可用状态.微软提供了一些例子(在System.Net.Sockets.SocketAsyncEventArgs类页面),如果存在大量挂起连接,则会导致堆栈溢出,这可以在任何实现其处理模型的系统上利用.

解决此问题的其他想法是创建一个调用处理程序方法的循环,其条件是值Socket.AcceptAsync返回等于false,并且如果值指示操作则中断循环(以允许延迟处理)正在异步完成(真实).但是,此解决方案还会导致堆栈溢出漏洞,因为与SocketAsyncEventArgs传递的关联的回调Socket.AcceptAsync在方法结束时有一个调用Socket.AcceptAsync,该调用还有一个用于立即可用,同步接受的连接的循环.

正如您所看到的,这是一个非常可靠的问题,我还没有找到一个不涉及System.Threading.ThreadPool并创建大量其他方法和调度处理的好解决方案.据我所知,与之相关的异步套接字模型Socket.AcceptAsync需要的内容要多于MSDN上的示例中所示的内容.

有没有人有一个干净有效的解决方案来处理从Socket.AcceptAsync同步接受的立即挂起的连接,而无需创建单独的线程来处理连接而不使用递归?

Luc*_*ero 7

我不会使用AcceptAsync,而是BeginAccept/ EndAccept,并且正确地实现公共异步模式,即检查CompletedSynchronously以避免回调线程中的回调完成的操作.

另请参见AsyncCallBack CompletedSynchronously


编辑有关使用要求AcceptAsync:

MSDN文档明确地说,回调将不会被调用了其同步完成操作.这与始终调用回调的常见异步模式不同.

如果I/O操作处于挂起状态,则返回true.操作完成后,将引发e参数上的SocketAsyncEventArgs.Completed事件.如果I/O操作同步完成,则返回false.不会引发e参数上的SocketAsyncEventArgs.Completed事件,并且可以在方法调用返回后立即检查作为参数传递的e对象以检索操作的结果.

我目前没有看到循环如何解决堆栈溢出问题.也许你可以更具体地解决导致问题的代码?


编辑2:我正在考虑这样的代码(只是关于AcceptAsync,其余只是为了让一个有效的应用程序尝试一下):

static void Main(string[] args) {
    Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    listenSocket.Bind(new IPEndPoint(IPAddress.Loopback, 4444));
    listenSocket.Listen(100);
    SocketAsyncEventArgs e = new SocketAsyncEventArgs();
    e.Completed += AcceptCallback;
    if (!listenSocket.AcceptAsync(e)) {
        AcceptCallback(listenSocket, e);
    }
    Console.ReadKey(true);
}

private static void AcceptCallback(object sender, SocketAsyncEventArgs e) {
    Socket listenSocket = (Socket)sender;
    do {
        try {
            Socket newSocket = e.AcceptSocket;
            Debug.Assert(newSocket != null);
            // do your magic here with the new socket
            newSocket.Send(Encoding.ASCII.GetBytes("Hello socket!"));
            newSocket.Disconnect(false);
            newSocket.Close();
        } catch {
            // handle any exceptions here;
        } finally {
            e.AcceptSocket = null; // to enable reuse
        }
    } while (!listenSocket.AcceptAsync(e));
}
Run Code Online (Sandbox Code Playgroud)