Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Consuming a HTTP stream without reading one byte at a time

I have been trying to read data from the Twitter stream API using C#, and since sometimes the API will return no data, and I am looking for a near-realtime response, I have been hesitant to use a buffer length of more than 1 byte on the reader in case the stream doesn't return any more data for the next day or two.

I have been using the following line:

input.BeginRead(buffer, 0, buffer.Length, InputReadComplete, null); 
//buffer = new byte[1]

Now that I plan to scale the application up, I think a size of 1 will result in a lot of CPU usage, and want to increase that number, but I still don't want the stream to just block. Is it possible to get the stream to return if no more bytes are read in the next 5 seconds or something similar?

like image 415
HenryZhang Avatar asked Dec 12 '12 00:12

HenryZhang


People also ask

Can I read the httpcontext request body without consuming it?

After installation you can read the HttpContext request body without consuming it as follows We are happy with the .Net core's Middlewares and ActionFilters.

How to read an empty stream in MVC?

A stream is like a one-time message, it will be gone, as soon as you read it. The HttpContext.Request.Body is also a stream, by reading it in middleware 1 , you will end up with an empty stream in the MVC middleware if the pipeline's order is as follows : The known solution is to read the stream and then put back in its place.

Is it possible to use streams with an API?

This is totally a separate process. Our API may or may not work with streams but this doesn’t affect the client side. In the client application, we can use streams to prepare a request body or to read from a response regardless of the API implementation.

Why does getcompanieswithstream use less memory?

This obviously means that we are going to use less memory because we don’t have to keep an entire content inside the memory. Also, this affects performance since we can work with the data faster. To implement this improvement, all we have to do is to modify the GetAsync method in the GetCompaniesWithStream method:


1 Answers

Async Option

You can use a timer in the async callback method to complete the operation if no bytes are received for e.g. 5 seconds. Reset the timer every time bytes are received. Start it before BeginRead.

Sync Option

Alternatively, you can use the ReceiveTimeout property of the underlying socket to establish a maximum time to wait before completing the read. You can use a larger buffer and set the timeout to e.g. 5 seconds.

From the MSDN documentation that property only applies to a synchronous read. You could perform a synchronous read on a separate thread.

UPDATE

Here's rough, untested code pieced together from a similar problem. It will probably not run (or be bug-free) as-is, but should give you the idea:

private EventWaitHandle asyncWait = new ManualResetEvent(false);
private Timer abortTimer = null;
private bool success = false;

public void ReadFromTwitter()
{
    abortTimer = new Timer(AbortTwitter, null, 50000, System.Threading.Timeout.Infinite);

    asyncWait.Reset();
    input.BeginRead(buffer, 0, buffer.Length, InputReadComplete, null);
    asyncWait.WaitOne();            
}

void AbortTwitter(object state)
{
    success = false; // Redundant but explicit for clarity
    asyncWait.Set();
}

void InputReadComplete()
{
    // Disable the timer:
    abortTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
    success = true;
    asyncWait.Set();
}
like image 76
Eric J. Avatar answered Sep 20 '22 10:09

Eric J.