回调方法间接回调自身

时间:2014-01-02 04:48:36

标签: c# recursion asynccallback

在C#类中,以下格式用于异步读取套接字中的数据。

正如您在代码中看到的,它使用AsyncReceive从套接字读取数据。它在收到数据时回拨OnDataReception

OnDataReception中,如果对话尚未完成,则处理收到的数据并再次调用ListenForData

此代码段是否会创建任何类型的无限递归? (功能或线程)

class ClientConnection{
  Socket socket = ...
  SocketAsyncEventArgs args = ...
  args.Completed += new EventHandler<SocketAsyncEventArgs>(OnDataReception);
  ...

  public void ListenForData(){
    ...
    socket.ReceiveAsync(args);
    ...
  }

  public void OnDataReception(Object obj, SocketAsyncEventArgs args){
    ...

    // if conversation is finished, return

    // else call ListenForData() again...
  }

  ...
}

3 个答案:

答案 0 :(得分:1)

首先我想提一下,问题类似于How does this not cause a stack overflow?

现在具体谈谈您的问题:代码片段使用的线程数量受用于执行ReceiveAsync的线程池中可用线程数的限制。如果先前调用异步方法返回,则刚生成新线程。

进一步OnDataReception每次都会调用ListenForDataListenForData而不是直接调用OnDataReception。这意味着,两种方法之间没有直接的函数递归。在后台线程中执行的ReceiveAsync不会产生嵌套的堆栈帧。

所以在我看来代码中没有隐藏的递归。

答案 1 :(得分:1)

MSDN Documentation on Socket.ReceiveAsync

  

如果I / O操作处于挂起状态,则返回true 。该   将引发 e 参数上的SocketAsyncEventArgs.Completed事件   完成手术后。

     

如果I / O操作,则返回false   同步完成。在这种情况下,The    e 参数上的SocketAsyncEventArgs.Completed事件不会发生   引发并且可以检查作为参数传递的 e 对象   在方法调用返回后立即检索结果   操作。

要回答您的问题,它不会创建无限循环/递归。

每次拨打ListenForData时,您的OnDataReception方法只会拨打ReceiveAsync。由于您在ListenForData中呼叫OnDataReception而不是在循环中,它将如下所示:

ListenForData called!
(time elapses)
OnDataReception called!
ListenForData called!
(time elapses)
OnDataReception called!
ListenForData called!
...

这几乎与使用Socket.BeginReceive相同,传递AsyncCallback然后在回调中调用Socket.EndReceive后跟另一个Socket.BeginReceive。它是无限期循环,但不是无限循环。

请参阅:

void StartReceiving()
{
  // Start receiving asynchronously...
  socket.BeginReceive(recvBuffer, 0, recvBuffer.Length, SocketFlags.None, OnDataReceived, null);
}

void OnDataReceived(IAsyncResult result)
{
  // Finish receiving this data.
  var numberOfBytesReceived = socket.EndReceive(result);

  // Start receiving asynchronously again...
  if(numberOfBytesReceived > 0 && socket.Connected)
    socket.BeginReceive(recvBuffer, 0, recvBuffer.Length, SocketFlags.None, OnDataReceived, null);
}

答案 2 :(得分:0)

这不会产生任何无限期的递归,但您可以稍微更改架构以获得有效的资源利用率。 您可以使用两个不同的线程进行监听和转换,因为无论转换结果如何,程序都需要监听端口。