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);
}
}
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
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With