Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this an async reading?

Tags:

c#

I have a listen() function which is reading the networkstream and a callback function newDataRecievedCallback.

I call a method BeginRead which is Async, but I call the same method in the callback function again. Isn't it then sync logic?

Is there anotherway to do it?

    private void listen()
    {
        networkStream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(newDataRecievedCallback), null);
    }

    private void newDataRecievedCallback(IAsyncResult rst)
    {
        try
        {
            int recievedDataSize = tcpClient.Client.Receive(buffer);
            recievedData = convertToString(buffer, incomeDataSize);

            //End Read
            networkStream.EndRead(rst);
            cleanBuffer();
            parseXMLData(recievedData);

            //Hier I call the same async method
            networkStream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(newDataRecievedCallback), null);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
like image 490
Racooon Avatar asked May 25 '26 17:05

Racooon


2 Answers

If BeginRead always completes asynchronously then calling it again in the callback will still be asynchronous.

However BeginRead will sometimes complete synchronously (check IAsyncResult.CompletedSynchronously), thus your code is vulnerable to stack overflows when you get unlucky. For example, this could happen in one thread: newDataRecievedCallback -> BeginRead -> newDataRecievedCallback -> BeginRead and so on.

The proper way to use BeginRead is to use a pattern similar to the one below (this is a code snippet from C# 4.0 in a Nutshell). In essence, you should always check if the method completed synchronously and then act appropriately.

void Read()            // Read in a nonblocking fashion.
{
  while (true)
  {
    IAsyncResult r = _stream.BeginRead
     (_data, _bytesRead, _data.Length - _bytesRead, ReadCallback, null);

    // This will nearly always return in the next line:
    if (!r.CompletedSynchronously) return;   // Handled by callback
    if (!EndRead (r)) break;
  }
  Write();
}

void ReadCallback (IAsyncResult r)
{
  try
  {
    if (r.CompletedSynchronously) return;
    if (EndRead (r))
    {
      Read();       // More data to read!
      return;
    }
    Write();
  }
  catch (Exception ex) { ProcessException (ex); }
}

bool EndRead (IAsyncResult r)   // Returns false if there’s no more data
{
  int chunkSize = _stream.EndRead (r);
  _bytesRead += chunkSize;
  return chunkSize > 0 && _bytesRead < _data.Length;   // More to read
}
like image 116
Ilian Avatar answered May 27 '26 06:05

Ilian


It is still asynch because your call to networkStream.BeginRead does not block. You make the call and then exit the function. Yes, it will be called again but still in an asynch manner.

Is there another way? Yes, hundreds of ways. Your code isn't bad. It just seems a bit tightly coupled in that your asynch handler is performing its own management as well as processing data. A cleaner way would be to have some sort of controller which your newDataRecievedCallback would notify via a delegate, and pass the data to it for processing. The controller would also be responsible for spawning the next asynch process. A separate controller could also pass the received data for processing without blocking more asynch calls.

like image 23
Paul Sasik Avatar answered May 27 '26 06:05

Paul Sasik



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!