Question

In a C# class, the following format is used for reading data from a socket asynchronously.

As you can see in the code, it uses AsyncReceive to read data from a socket. It calls back OnDataReception when data is received.

In OnDataReception, received data is processed and again calls ListenForData if the conversation is not finished yet.

Does this code snippet create any kind of indefinite recursion? (functions or threads)

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...
  }

  ...
}
Was it helpful?

Solution

First I like to mention, that the question is similar to How does this not cause a stack overflow?.

Now to be specific on your questions: The amount of threads used by the code snippet is constrained by the number of threads available in the thread pool used to execute ReceiveAsync. New threads are just produced, if a previous call to the async method returned.

Further OnDataReception does call ListenForData every time. ListenForData instead does not directly call OnDataReception. This means, there is no direct functional recursion between the two methods. ReceiveAsync executed in a background-thread does not produce nested stack-frames.

So in my opinion there are no hidden recursions in the code.

OTHER TIPS

Per MSDN Documentation on Socket.ReceiveAsync:

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. In this case, 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.

To answer your question, no it will not create an infinite loop/recursion.

Your ListenForData method will only call OnDataReception once per call to ReceiveAsync. Since you are calling ListenForData in OnDataReception and not in a loop, it will look like this:

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

This is almost identical to using Socket.BeginReceive, passing an AsyncCallback and then calling Socket.EndReceive followed by another Socket.BeginReceive in the callback. It's an indefinite loop but not an infinite one.

See:

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

This would not produce any indefinite recursion, but you can change the architecture slightly for the effective resource utilization. You could use two different threads for listening and the conversion, since the program need to listen the port irrespective of the conversion result.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top