const_ref
const_ref

Reputation: 4096

Monitoring network stream for new data

I am writing an application that is interested in the status information from certain network devices. One of the devices provides the status information through Http and uses a multipart message; The first time you query the information it sends down the whole status and from then on whenever the status of the device changes a new multipart message is sent down the stream with just the changes.

I am using C# and am interested in using HttpClient or equivalent to open the stream, read all the information currently in the stream and then monitor this stream for when there is new information so that I can update the status information of the device accordingly in the application.

In essence the code I have looks something like this

using (var handler = new HttpClientHandler { Credentials = new NetworkCredential(username, password) })
{
    using (var client = new HttpClient(handler))
    {
        var task = client.GetStreamAsync(uri);

        task.Wait();

        var stream = task.Result;

        while(true)
        {
            byte[] bytes = ReadBytesFromStream(stream);

            DoSomethingWithBytes(bytes);
        }
}

The code in real life runs in a thread however and would need terminated correctly when told to.

The issue I am having is that when there is nothing in the stream the Read call on stream.ReadByte() blocks. If I put a ReadTimeout on the stream then when the Read call fails(i.e. when no new information is ready) then the CanRead property is set to false and I have to restart the process however in doing so recieve all the original status information again instead of only the elements that have changed.

Is there something that can be done to keep the stream alive until I tell it to terminate while being able to unblock on the read if no information is available? The reason I need to do this is since the application is multithreaded I need to terminate this code safely and the read is stopping the application from closing down.

Upvotes: 2

Views: 681

Answers (2)

Peter Duniho
Peter Duniho

Reputation: 70671

The right way to deal with the "I/O operation blocks my thread" problem is to use asynchronous I/O. .NET networking components offer a number of options here, but in your case you seem to be reading from a stream and even using (incorrectly) the GetStreamAsync() method, so the code can be cleaned up to handle both correctly and cleanly.

For example:

async Task ExecuteUriAsync(string username, string password, Uri uri)
{
    using (var handler = new HttpClientHandler { Credentials = new NetworkCredential(username, password) })
    {
        using (var client = new HttpClient(handler))
        {
            Stream stream = await client.GetStreamAsync(uri);
            byte[] buffer = new byte[10240];

            while(true)
            {
                int byteCount = await stream.ReadAsync(buffer, 0, buffer.Length);

                if (byteCount == 0)
                {
                    // end-of-stream...must be done with the connection
                    return;
                }
                DoSomethingWithBytes(bytes, byteCount);
            }
        }
    }
}

Your post is vague on what your previous ReadBytesFromStream() method did, and what DoSomethingWithBytes() does, but presumably you can figure out how to integrate that logic in the above.

Upvotes: 0

const_ref
const_ref

Reputation: 4096

Instead of using HttpClient I used an HttpWebRequest and set KeepAlive to true and AllowReadStreamBuffering properties to true. This keeps the stream alive and allows you to read bytes as of when they become available.

By keeping a reference to the network stream returned from GetResponseStream we can call Dispose on the NetworkStream which interrupts any reads that are currently taking place otherwise the read can block for as long as it needs to i.e. until it recieves data which solves the thread lifetime issues.

Upvotes: 2

Related Questions