Getting IOException with NetworkStream.BeginRead()

1.1k views Asked by At

When running this code:

private async void StartChat(Object obj)
{
    TcpClient me = (TcpClient)obj;
    UpdateChatBox("Attempting read from server.");
    myBuffer = new byte[BUFFER_SIZE];

    while (true)
    {
        var myStream = me.GetStream();
        myStream.BeginRead(myBuffer, 0, BUFFER_SIZE, new AsyncCallback(UpdateChatBoxAsync), myStream);

        if (messageToSend)
        {
            await myStream.WriteAsync(myMessage, 0, myMessage.Length);
        }                
    }
}

I am receiving the following IO Exception from BeginRead:

Unable to read data from the transport connection: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.

Here is the callback method for BeginRead:

private void UpdateChatBoxAsync(IAsyncResult result)
{
    var stream = result.AsyncState as NetworkStream;
    int bytesRead = stream.EndRead(result);

    if (bytesRead > 0)
    {
        String newMessage = NetworkUtils.GetString(myBuffer);
        UpdateChatBox(newMessage);
    }
}

Can someone please shed some light as to the reason this exception is being raised? I tried recreating the buffer each time at the start of the while loop, but while that worked in not raising the exception, I would not receive messages from the server.

I also attempted to reset myBuffer to an empty array at the end of UpdateChatBoxAsync, this did not work either.

Any help would be appreciated.

2

There are 2 answers

3
usr On BEST ANSWER

You're running an infinite loop without any throttling. You are issuing async read calls as fast as the CPU can do it. This creates unlimited amounts of outstanding operations.

You are supposed to issue the next read when the last one has completed (most commonly done from the callback).

By just adding

if (myStream.DataAvailable)

you avoid the read but still burn one CPU core. This is just a mitigation for one of the symptoms. Fix the root cause instead.

It seems you should not be doing async IO at all because you don't have a problem with blocking. You're blocking a thread and burning 100% of a core. If that was acceptable, don't even bother with async IO.

Or, use await ReadAsync.

1
TGreg On

I have found my solution.

Before trying the BeginRead I check to see if the stream has any data available using NetworkStream.DataAvailable or in my case myStream.DataAvailable

So the new working block of code looks like

if (myStream.DataAvailable){
    myStream.BeginRead(myBuffer, 0, BUFFER_SIZE, new AsyncCallback(UpdateChatBoxAsync), myStream);
}