c# - 使用 System.Net.Sockets.Socket.AcceptAsync 模型时发生堆栈溢出

标签 c# sockets asynchronous

关于 C# 和 .NET 的 System.Net.Sockets.Socket.AcceptAsync方法,需要处理“false”的返回值,以便处理来自同步处理连接的立即可用的 SocketAsyncEventArgs 状态。 Microsoft 提供了示例(可在 System.Net.Sockets.SocketAsyncEventArgs 类页面中找到),如果存在大量未决连接,这些示例将导致堆栈溢出,可在任何实现它们的系统上加以利用处理模型。

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

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

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

最佳答案

我不会使用 AcceptAsync,而是使用 BeginAccept/EndAccept,并正确实现常见的异步模式,即检查CompletedSynchronously 以避免在回调线程中对已完成的操作进行回调。

另见 AsyncCallBack CompletedSynchronously


编辑关于使用 AcceptAsync 的要求:

MSDN documentation明确表示不会为同步完成的操作调用回调。这与始终调用回调的常见异步模式不同。

Returns true if the I/O operation is pending. The SocketAsyncEventArgs.Completed event on the e parameter will be raised upon completion of the operation. Returns false if the I/O operation completed synchronously. The SocketAsyncEventArgs.Completed event on the e parameter will not be raised and the e object passed as a parameter may be examined immediately after the method call returns to retrieve the result of the operation.

我目前不明白循环为什么不能解决堆栈溢出问题。也许您可以更具体地说明导致问题的代码?


编辑 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));
}

关于c# - 使用 System.Net.Sockets.Socket.AcceptAsync 模型时发生堆栈溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3954668/

相关文章:

c# - 没有 session 关闭的FTP Webrequest多个文件

c# - 为什么 .NET 与 Windows 操作系统是分开的?

c++ - 为什么我们在 Boost.ASIO 中需要很多接受器?

python - 在 Python 中使用 s.recv() 时出现奇怪的错误

javascript - 如何在 Node.js 函数中应用 Promise

c# - System.IO.FileNotFoundException : myCSharpDemoCalc\work\MyCSharpDemoCalc. j4n.dll

c# - 以编程方式创建 CSS 类 ASP.Net

java - 套接字连接请求被拒绝

java - 异步方法抛出异常是否合理?

node.js - 如何等待流完成管道? ( Node )