Click here to Skip to main content
15,880,608 members
Articles / Web Development / ASP.NET
Article

Bandwidth throttling

Rate me:
Please Sign up or sign in to vote.
4.75/5 (59 votes)
2 Apr 2007CPOL2 min read 273.8K   8.1K   139   61
Save bandwidth and get QoS with bandwidth throttling.

Screenshot - screen.jpg

Introduction

Hosting a website can be fun. But, when you offer big downloads or streaming media, you do not want a visitor to eat up the full bandwidth. Or, maybe, you want to offer a premium account from where users can download without limitation, and a free account where users cannot download faster than 50 kb/s. Here is where throttling comes in.

Bandwidth throttling helps provide quality of service (QoS) by limiting network congestion and server crashes. For example, you make sure a connection does not get more than an X number of bytes per second.

The purpose of this article is to show how to use bandwidth throttling, with a small helper class.

Using the code

Within the source code, you will find a class named ThrottledStream. This class is derived from the abstract Stream that can be found in the System.IO namespace. In the constructor, it accepts a base stream to throttle. Here is a small line of code that shows how to instantiate a ThrottledStream:

C#
Stream throttledStream = new ThrottledStream(Response.OutputStream, 1024);

Now, everything you do with the throttledStream will be limited to 1024 bytes per second, and will be send to or read from the OutputStream that is a member of the Response property that exists within an ASP.NET page.

Because the ThrottledStream is derived from the abstract Stream class, it is easy to add throttling to an existing application or website. For example, when you have a process that sends file content over a Stream and you want to enable bandwidth throttling, you only have to change the initialization of the destination stream.

The old code can look like this:

C#
Stream sourceStream;
Stream destinationStream;

try
{
    sourceStream = new FileStream(@"c:\myfile.bin", 
                       FileMode.Open, FileAccess.Read, FileShare.Read);
    destinationStream = new NetworkStream(mySocket, false);

    byte[] buffer = new byte[1024];
    int readCount = sourceStream.Read(buffer, 0, BufferSize);

    while (readCount > 0)
    {
        destinationStream.Write(buffer, 0, readCount);
        readCount = sourceStream.Read(buffer, 0, BufferSize);
    }
}
finally
{
    if (destinationStream != null)
    {
        destinationStream.Close();
    }
 
    if (sourceStream != null)
    {
        sourceStream.Close();
    }
}

Now, we can easily add throttling support to this process. We only need to change the initialization:

C#
...

Stream originalDestinationStream = new NetworkStream(mySocket, false);
destinationStream = new ThrottledStream(originalDestinationStream, 51200);

...

By adding only one line of code, this full process is throttled to 50 kb/s (51200 b/s). Now, we go even a step further and add throttling that is based on a membership:

C#
...

long bps;

switch( user.Membership )
{
    case MembershipLevel.Bronze:
        bps = 51200;
        break;

    case MembershipLevel.Silver:
        bps = 102400;
        break;

    case MembershipLevel.Gold:
        bps = 153600;
        break;

    case MembershipLevel.Platina:
        bps = ThrottledStream.Infinite;
        break;
}

Stream originalDestinationStream = new NetworkStream(mySocket, false);
destinationStream = new ThrottledStream(originalDestinationStream, bps);

...

Here, we have a situation where a Bronze membership will give you 50 kb/s, Silver 100 kb/s, Gold 150 kb/s, and Platina infinitive - no throttling.

Points of interest

Bandwidth throttling can improve the QoS of your server, and allows you to control the bandwidth for a specified connection. The helper class named ThrottledStream is very easy to use, and can be used in existing scenarios.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Sogyo
Netherlands Netherlands
Pieter Joost is a sr. IT consultant at Sogyo. He is recently awarded as Microsoft Visual C# MVP. He's active in the software development community as a speaker and boardmember of devnology.nl and dotned.nl

Comments and Discussions

 
Questionwhen will you reset time and bytecount? Pin
tim40830-Jan-08 18:21
tim40830-Jan-08 18:21 
QuestionIs this really a throttling technique? Pin
Kelmen Wong27-Sep-07 23:20
Kelmen Wong27-Sep-07 23:20 
AnswerRe: Is this really a throttling technique? Pin
P.J. van de Sande28-Sep-07 0:51
P.J. van de Sande28-Sep-07 0:51 
GeneralGeneral throttling Pin
Bit-Smacker17-Aug-07 7:59
Bit-Smacker17-Aug-07 7:59 
Generalone small bug Pin
FelixWatts15-Jul-07 12:16
FelixWatts15-Jul-07 12:16 
GeneralRe: one small bug - another one Pin
AndrewSmith21-May-09 19:08
AndrewSmith21-May-09 19:08 
GeneralThanks - I used it. Pin
FelixWatts15-Jul-07 8:37
FelixWatts15-Jul-07 8:37 
QuestionI'm sorry to say the solution is NOT correct Pin
TonyTonyQ9-Apr-07 23:02
professionalTonyTonyQ9-Apr-07 23:02 
Good work and interesting subject. But after I looked into your codes, I think the solution you use are NOT good.
Your solution is transfer some data to client(in this time period, bandwidth is not controled) and record the spent time as time A, then calculate the time B for transfering the data above using the setted max bandwidth.
Then get a time C which is equal to (time B - time A), let the thread sleep for the time period C.

The solution is very simple but it will cause strange problem and it will become useless.

I just change the bufferSize from 8192 to 8192000 in the default.aspx.cs, line 19, yes, use about 8MB for buffer. Then run the program, the result is it will give me the first 8M data of the 10MB file in about 1 second!(Because I run it on my local machine) And then sleep about 163 secondes then give me the left 2MB of data. It's funny.

So I should say the solution is only work when the buffer size is small! It makes no sense when the buffer size is set to a large number.

I'd like to get a better solution from you, since I'm also very interesting in this kind of programming.

Regards.
AnswerRe: I'm sorry to say the solution is NOT correct Pin
P.J. van de Sande10-Apr-07 0:19
P.J. van de Sande10-Apr-07 0:19 
GeneralRe: I'm sorry to say the solution is NOT correct Pin
TonyTonyQ10-Apr-07 17:02
professionalTonyTonyQ10-Apr-07 17:02 
GeneralRe: I'm sorry to say the solution is NOT correct Pin
AndrewSmith21-May-09 19:12
AndrewSmith21-May-09 19:12 
AnswerRe: I'm sorry to say the solution is NOT correct Pin
Paul A. Howes10-Apr-07 5:40
Paul A. Howes10-Apr-07 5:40 
GeneralRe: I'm sorry to say the solution is NOT correct Pin
P.J. van de Sande10-Apr-07 9:23
P.J. van de Sande10-Apr-07 9:23 
General5 stars code Pin
ntorrisi4-Apr-07 8:42
ntorrisi4-Apr-07 8:42 
GeneralRe: 5 stars code Pin
P.J. van de Sande4-Apr-07 20:55
P.J. van de Sande4-Apr-07 20:55 
QuestionClient Side? Pin
NickHD3-Apr-07 17:07
NickHD3-Apr-07 17:07 
AnswerRe: Client Side? Pin
P.J. van de Sande3-Apr-07 21:36
P.J. van de Sande3-Apr-07 21:36 
GeneralRe: Client Side? Pin
Bit-Smacker17-Aug-07 7:43
Bit-Smacker17-Aug-07 7:43 
Generalhelpful article Pin
Christiaan van Bergen2-Apr-07 21:25
professionalChristiaan van Bergen2-Apr-07 21:25 
Generaluseful Pin
lxwde2-Apr-07 19:33
lxwde2-Apr-07 19:33 
GeneralRe: useful Pin
P.J. van de Sande3-Apr-07 0:36
P.J. van de Sande3-Apr-07 0:36 
GeneralInteresting, but.. Pin
Rafael Nicoletti2-Apr-07 11:03
Rafael Nicoletti2-Apr-07 11:03 
GeneralRe: Interesting, but.. Pin
Rei Miyasaka3-Apr-07 0:28
Rei Miyasaka3-Apr-07 0:28 
GeneralRe: Interesting, but.. Pin
P.J. van de Sande3-Apr-07 0:34
P.J. van de Sande3-Apr-07 0:34 
GeneralRe: Interesting, but.. Pin
Rei Miyasaka3-Apr-07 0:47
Rei Miyasaka3-Apr-07 0:47 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.