首页 > 解决方案 > c# AsyncSockets 从客户端套接字读取时递归

问题描述

我正在关注有关创建异步套接字服务器的 MSDN 教程(此处)。我需要服务器能够不断地收听来自客户端的消息,在查看了这里这里的答案之后,我最终得到了这样的结果:

        public static void ReadCallback(IAsyncResult ar)
        {
            String content = String.Empty;

            StateObject state = (StateObject)ar.AsyncState;
            Socket handler = state.workSocket;

            int bytesRead = handler.EndReceive(ar);

            if (bytesRead > 0)
            { 
                state.sb.Append(Encoding.ASCII.GetString(
                    state.buffer, 0, bytesRead));

                content = state.sb.ToString();
                if (content.IndexOf("<EOF>") > -1)
                {
                    // Message received, do something 
                    // ...
                }
                else
                {
                    // Not all data received. Get more
                    // ...
                }
            }

            // Continue waiting
            handler.BeginReceive(state.buffer, 0, SocketState.BufferSize, 0,
            new AsyncCallback(ReadCallback), state);            
        }

我的问题是,这种方法是否会无限增长堆栈,因为它有一个递归调用ReadCallback()

标签: c#socketsasynchronous

解决方案


我的问题是,这种方法是否会无限增长堆栈,因为它对 ReadCallback() 进行了递归调用?

不,它不会。根据定义,递归调用将涉及对另一个方法的调用,该方法将直接或间接涉及在该调用仍在进行时调用当前方法。

当使用可用于套接字 I/O 的许多异步技术中的任何一种时,当您启动新的接收操作时——例如通过调用Socket.BeginReceive()方法——您正在调用的方法通常不会导致当前方法在调用期间再次被调用进步。当前方法将在稍后收到更多数据时调用。

然而,有一个重要的警告:

  • 仅仅因为调用不是递归的,并不意味着您的回调不能被调用re-entrantly。也就是说,如果数据很快可用,则在当前调用回调完成之前,另一个线程可能会调用您的回调来处理接收到的数据的新缓冲区。

通常,BeginReceive()在完成所有数据处理之后,直到回调结束(就像您发布的代码示例一样)才再次调用来解决此问题。这确保了即使该方法确实被重入调用,当前调用要做的唯一事情就是返回给调用者,因此它不会与后续调用发生冲突。

还有另一个理论上的“陷阱”,但我有理由确定它不适用于这里。.NET 使用 IOCP 为套接字 API 实现异步 I/O。默认情况下,IOCP 将始终为完成分配一个新线程,从而防止递归。但是,如果 IOCP 客户端使用该FILE_SKIP_COMPLETION_PORT_ON_SUCCESS选项,IOCP 可以递归调用完成回调,而无需将完成排队到完成端口,如果在启动 I/O 操作时数据已经可用并等待读取。

我不认为 .NET 使用此选项,因此您不会遇到这种情况。但请注意,即使您这样做了,递归也不太可能变得很深,因为 CPU 通常处理数据的速度远远快于通过任何 I/O 设备(尤其是网络适配器)发送数据的速度。接收操作通常只需要另一个或两个回调来赶上可用数据。

底线是,只要您按照上面的方式实现代码,在您完全处理完当前完成的操作之前,您不会启动新的接收操作,您应该没有什么可担心的。


推荐阅读