1

I have a Task that should continuously read from a Tcp stream and place the data into a ConcurrentQueue for processing. Stepping through the function I notice that the ReadAsync Call does not return.

For reference there is no data currently going across the network but I would still like to attempt to read from the stream so long as the loop is active.

Receive Loop

If I step through this loop, I make it to the _stream.ReadAsync line and then the application window pops up skipping the rest of the loop.

        private async Task ReceiveLoop()
        {
            byte[] buffer = new byte[1024];
            while (_isConnected)
            {
                if(_stream != null && _stream.CanRead)
                {
                    try
                    {
                        int bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length);
                        if (bytesRead > 0)
                        {
                            byte[] receivedData = new byte[bytesRead];
                            Buffer.BlockCopy(buffer, 0, receivedData, 0, bytesRead);
                            if(_receiveQueue != null)
                            {
                                _receiveQueue.Enqueue(receivedData);
                            }
                        }
                    }
                    catch (ObjectDisposedException ex) 
                    {
                        // Log[Error] - ex
                        _isConnected = false;
                    }
                    catch(InvalidOperationException ex)
                    {
                        //Log[Warning] - ex
                    }
                }
                // Console.WriteLine("ReceiveLoop is alive");
            }
        }
3
  • What is calling this code? Sounds like something is not awaited somewhere. Side notes: _stream != null is always true. You should break out of the loop with if (bytesRead == 0) break; which will only happen if the socket is closed. Instead of _isConnected just break; out of the loop or throw. Commented Sep 17 at 20:46
  • The answer depends on how you're calling ReceiveLoop(). It's implied it's a console app, and you're simply "falling through" to the end. There is no "standard wait state" for a console app; and since you did not mention yours ... (Try it from a Windows form or other "window" which has a built-in "loop") Commented Sep 17 at 20:48
  • 1
    Side note; this is not a great way of handling network buffering. If it is low throughout, it'll work, sure, but: it'll struggle beyond fairly basic scenarios. Also, keep in mind that TCP is a streaming protocol, not a message protocol - your receive queue needs to be considered as a whole. Commented Sep 17 at 22:44

1 Answer 1

3

I notice that the ReadAsync Call does not return.

That is normal and expected. ReadAsync has four expected outcomes:

  • either immediately or after some time (synchronous for Read, asynchronous for ReadAsync) reads some positive amount of data
  • it returns a non-positive result to indicate an EOF condition
  • it results in an exception for a non-graceful failure
  • in a niche zero-length read case (provided a zero-length buffer to populate), it returns zero to indicate that data is now available to be read, or an EOF - perform another read with a non-empty buffer to find out which (this scenario is somewhat OS-dependent)

If no data is available, the stream hasn't terminated, and nothing has exploded: we expect ReadAsync to simply not return (or rather: to return an incomplete awaitable).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.