• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<html>
2<head>
3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
4<title>Rate Limiting ��</title>
5<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
6<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
7<link rel="home" href="../../index.html" title="Chapter 1. Boost.Beast">
8<link rel="up" href="../using_io.html" title="Networking">
9<link rel="prev" href="timeouts.html" title="Timeouts ��">
10<link rel="next" href="layered_streams.html" title="Layered Streams">
11</head>
12<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
13<table cellpadding="2" width="100%"><tr>
14<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
15<td align="center"><a href="../../../../../../index.html">Home</a></td>
16<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
17<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
18<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
19<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
20</tr></table>
21<hr>
22<div class="spirit-nav">
23<a accesskey="p" href="timeouts.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../using_io.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="layered_streams.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
24</div>
25<div class="section">
26<div class="titlepage"><div><div><h3 class="title">
27<a name="beast.using_io.rate_limiting"></a><a class="link" href="rate_limiting.html" title="Rate Limiting ��">Rate Limiting ��</a>
28</h3></div></div></div>
29<p>
30        The <a class="link" href="../ref/boost__beast__basic_stream.html" title="basic_stream"><code class="computeroutput"><span class="identifier">basic_stream</span></code></a>
31        class template supports an additional <code class="computeroutput"><span class="identifier">RatePolicy</span></code>
32        template parameter. Objects of this type must meet the requirements of <a class="link" href="../concepts/RatePolicy.html" title="RatePolicy"><span class="emphasis"><em>RatePolicy</em></span></a>.
33        They are used to implement rate limiting or bandwidth management. The default
34        policy for <code class="computeroutput"><span class="identifier">basic_stream</span></code> and
35        <code class="computeroutput"><span class="identifier">tcp_stream</span></code> is <a class="link" href="../ref/boost__beast__unlimited_rate_policy.html" title="unlimited_rate_policy"><code class="computeroutput"><span class="identifier">unlimited_rate_policy</span></code></a>, which places
36        no limits on reading and writing. The library comes with the <a class="link" href="../ref/boost__beast__simple_rate_policy.html" title="simple_rate_policy"><code class="computeroutput"><span class="identifier">simple_rate_policy</span></code></a>, allowing for
37        independent control of read and write limits expressed in terms of bytes
38        per second. The follow code creates an instance of the basic stream with
39        a simple rate policy, and sets the read and write limits:
40      </p>
41<pre class="programlisting"><span class="comment">// To declare a stream with a rate policy, it is necessary to</span>
42<span class="comment">// write out all of the template parameter types.</span>
43<span class="comment">//</span>
44<span class="comment">// `simple_rate_policy` is default constructible, but</span>
45<span class="comment">// if the choice of RatePolicy is not DefaultConstructible,</span>
46<span class="comment">// an instance of the type may be passed to the constructor.</span>
47
48<span class="identifier">basic_stream</span><span class="special">&lt;</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">any_io_executor</span><span class="special">,</span> <span class="identifier">simple_rate_policy</span><span class="special">&gt;</span> <span class="identifier">stream</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">);</span>
49
50<span class="comment">// The policy object, which is default constructed, or</span>
51<span class="comment">// decay-copied upon construction, is attached to the stream</span>
52<span class="comment">// and may be accessed through the function `rate_policy`.</span>
53<span class="comment">//</span>
54<span class="comment">// Here we set individual rate limits for reading and writing</span>
55
56<span class="identifier">stream</span><span class="special">.</span><span class="identifier">rate_policy</span><span class="special">().</span><span class="identifier">read_limit</span><span class="special">(</span><span class="number">10000</span><span class="special">);</span> <span class="comment">// bytes per second</span>
57
58<span class="identifier">stream</span><span class="special">.</span><span class="identifier">rate_policy</span><span class="special">().</span><span class="identifier">write_limit</span><span class="special">(</span><span class="number">850000</span><span class="special">);</span> <span class="comment">// bytes per second</span>
59</pre>
60<p>
61        More sophisticated rate policies can be implemented as user-defined types
62        which meet the requirements of <a class="link" href="../concepts/RatePolicy.html" title="RatePolicy"><span class="emphasis"><em>RatePolicy</em></span></a>.
63        Here, we develop a rate policy that measures the instantaneous throughput
64        of reads and writes. First we write a small utility class that applies an
65        exponential smoothing function to a series of discrete rate samples, to calculate
66        instantaneous throughput.
67      </p>
68<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">window</span>
69<span class="special">{</span>
70    <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">value_</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
71
72    <span class="comment">// The size of the exponential window, in seconds.</span>
73    <span class="comment">// This should be a power of two.</span>
74
75    <span class="keyword">static</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="keyword">constexpr</span> <span class="identifier">Window</span> <span class="special">=</span> <span class="number">4</span><span class="special">;</span>
76
77<span class="keyword">public</span><span class="special">:</span>
78    <span class="comment">/** Returns the number of elapsed seconds since the given time, and adjusts the time.
79
80        This function returns the number of elapsed seconds since the
81        specified time point, rounding down. It also moves the specified
82        time point forward by the number of elapsed seconds.
83
84        @param since The time point from which to calculate elapsed time.
85        The function will modify the value, by adding the number of elapsed
86        seconds to it.
87
88        @return The number of elapsed seconds.
89    */</span>
90    <span class="keyword">template</span><span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">Clock</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Duration</span><span class="special">&gt;</span>
91    <span class="keyword">static</span>
92    <span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span>
93    <span class="identifier">get_elapsed</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">time_point</span><span class="special">&lt;</span><span class="identifier">Clock</span><span class="special">,</span> <span class="identifier">Duration</span><span class="special">&gt;&amp;</span> <span class="identifier">since</span><span class="special">)</span> <span class="keyword">noexcept</span>
94    <span class="special">{</span>
95        <span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">elapsed</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">duration_cast</span><span class="special">&lt;</span>
96            <span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">&gt;(</span><span class="identifier">Clock</span><span class="special">::</span><span class="identifier">now</span><span class="special">()</span> <span class="special">-</span> <span class="identifier">since</span><span class="special">);</span>
97        <span class="identifier">since</span> <span class="special">+=</span> <span class="identifier">elapsed</span><span class="special">;</span>
98        <span class="keyword">return</span> <span class="identifier">elapsed</span><span class="special">;</span>
99    <span class="special">}</span>
100
101    <span class="comment">/// Returns the current value, after adding the given sample.</span>
102    <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span>
103    <span class="identifier">update</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">sample</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span> <span class="identifier">elapsed</span><span class="special">)</span> <span class="keyword">noexcept</span>
104    <span class="special">{</span>
105        <span class="comment">// Apply exponential decay.</span>
106        <span class="comment">//</span>
107        <span class="comment">// This formula is fast (no division or multiplication) but inaccurate.</span>
108        <span class="comment">// It overshoots by `n*(1-a)/(1-a^n), where a=(window-1)/window`.</span>
109        <span class="comment">// Could be good enough for a rough approximation, but if relying</span>
110        <span class="comment">// on this for production please perform tests!</span>
111
112        <span class="keyword">auto</span> <span class="identifier">count</span> <span class="special">=</span> <span class="identifier">elapsed</span><span class="special">.</span><span class="identifier">count</span><span class="special">();</span>
113        <span class="keyword">while</span><span class="special">(</span><span class="identifier">count</span><span class="special">--)</span>
114            <span class="identifier">value_</span> <span class="special">-=</span> <span class="special">(</span><span class="identifier">value_</span> <span class="special">+</span> <span class="identifier">Window</span> <span class="special">-</span> <span class="number">1</span><span class="special">)</span> <span class="special">/</span> <span class="identifier">Window</span><span class="special">;</span>
115        <span class="identifier">value_</span> <span class="special">+=</span> <span class="identifier">sample</span><span class="special">;</span>
116        <span class="keyword">return</span> <span class="identifier">value_</span> <span class="special">/</span> <span class="identifier">Window</span><span class="special">;</span>
117    <span class="special">}</span>
118    <span class="comment">/// Returns the current value</span>
119    <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span>
120    <span class="identifier">value</span><span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span>
121    <span class="special">{</span>
122        <span class="keyword">return</span> <span class="identifier">value_</span> <span class="special">/</span> <span class="identifier">Window</span><span class="special">;</span>
123    <span class="special">}</span>
124<span class="special">};</span>
125</pre>
126<p>
127        Then we define our rate policy object. We friend the type <a class="link" href="../ref/boost__beast__rate_policy_access.html" title="rate_policy_access"><code class="computeroutput"><span class="identifier">rate_policy_access</span></code></a> to allow our
128        implementation to be private, but still allow the <code class="computeroutput"><span class="identifier">basic_stream</span></code>
129        access to call the required functions. This lets us avoid having to write
130        a cumbersome friend declaration for the <code class="computeroutput"><span class="identifier">basic_stream</span></code>
131        class template. Public members of rate policy objects become part of the
132        stream object's interface, through a call to <code class="computeroutput"><span class="identifier">rate_policy</span></code>.
133      </p>
134<pre class="programlisting"><span class="comment">/** A RatePolicy to measure instantaneous throughput.
135
136    This measures the rate of transfer for reading and writing
137    using a simple exponential decay function.
138*/</span>
139<span class="keyword">class</span> <span class="identifier">rate_gauge</span>
140<span class="special">{</span>
141    <span class="comment">// The clock used to measure elapsed time</span>
142    <span class="keyword">using</span> <span class="identifier">clock_type</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">steady_clock</span><span class="special">;</span>
143
144    <span class="comment">// This implements an exponential smoothing window function.</span>
145    <span class="comment">// The value `Seconds` is the size of the window in seconds.</span>
146
147    <span class="identifier">clock_type</span><span class="special">::</span><span class="identifier">time_point</span> <span class="identifier">when_</span><span class="special">;</span>
148    <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">read_bytes_</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
149    <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">write_bytes_</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
150    <span class="identifier">window</span> <span class="identifier">read_window_</span><span class="special">;</span>
151    <span class="identifier">window</span> <span class="identifier">write_window_</span><span class="special">;</span>
152
153    <span class="comment">// Friending this type allows us to mark the</span>
154    <span class="comment">// member functions required by RatePolicy as private.</span>
155    <span class="keyword">friend</span> <span class="keyword">class</span> <span class="identifier">rate_policy_access</span><span class="special">;</span>
156
157    <span class="comment">// Returns the number of bytes available to read currently</span>
158    <span class="comment">// Required by RatePolicy</span>
159    <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span>
160    <span class="identifier">available_read_bytes</span><span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span>
161    <span class="special">{</span>
162        <span class="comment">// no limit</span>
163        <span class="keyword">return</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">&gt;::</span><span class="identifier">max</span><span class="special">)();</span>
164    <span class="special">}</span>
165
166    <span class="comment">// Returns the number of bytes available to write currently</span>
167    <span class="comment">// Required by RatePolicy</span>
168    <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span>
169    <span class="identifier">available_write_bytes</span><span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span>
170    <span class="special">{</span>
171        <span class="comment">// no limit</span>
172        <span class="keyword">return</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span><span class="special">&gt;::</span><span class="identifier">max</span><span class="special">)();</span>
173    <span class="special">}</span>
174
175    <span class="comment">// Called every time bytes are read</span>
176    <span class="comment">// Required by RatePolicy</span>
177    <span class="keyword">void</span>
178    <span class="identifier">transfer_read_bytes</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">n</span><span class="special">)</span> <span class="keyword">noexcept</span>
179    <span class="special">{</span>
180        <span class="comment">// Add this to our running total of bytes read</span>
181        <span class="identifier">read_bytes_</span> <span class="special">+=</span> <span class="identifier">n</span><span class="special">;</span>
182    <span class="special">}</span>
183
184    <span class="comment">// Called every time bytes are written</span>
185    <span class="comment">// Required by RatePolicy</span>
186    <span class="keyword">void</span>
187    <span class="identifier">transfer_write_bytes</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">n</span><span class="special">)</span> <span class="keyword">noexcept</span>
188    <span class="special">{</span>
189        <span class="comment">// Add this to our running total of bytes written</span>
190        <span class="identifier">write_bytes_</span> <span class="special">+=</span> <span class="identifier">n</span><span class="special">;</span>
191    <span class="special">}</span>
192
193    <span class="comment">// Called approximately once per second</span>
194    <span class="comment">// Required by RatePolicy</span>
195    <span class="keyword">void</span>
196    <span class="identifier">on_timer</span><span class="special">()</span>
197    <span class="special">{</span>
198        <span class="comment">// Calculate elapsed time in seconds, and adjust our time point</span>
199        <span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">elapsed</span> <span class="special">=</span> <span class="identifier">window</span><span class="special">::</span><span class="identifier">get_elapsed</span><span class="special">(</span><span class="identifier">when_</span><span class="special">);</span>
200
201        <span class="comment">// Skip the update when elapsed==0,</span>
202        <span class="comment">// otherwise the measurement will have jitter</span>
203        <span class="keyword">if</span><span class="special">(</span><span class="identifier">elapsed</span><span class="special">.</span><span class="identifier">count</span><span class="special">()</span> <span class="special">==</span> <span class="number">0</span><span class="special">)</span>
204            <span class="keyword">return</span><span class="special">;</span>
205
206        <span class="comment">// Add our samples and apply exponential decay</span>
207        <span class="identifier">read_window_</span><span class="special">.</span><span class="identifier">update</span><span class="special">(</span><span class="identifier">read_bytes_</span><span class="special">,</span> <span class="identifier">elapsed</span><span class="special">);</span>
208        <span class="identifier">write_window_</span><span class="special">.</span><span class="identifier">update</span><span class="special">(</span><span class="identifier">write_bytes_</span><span class="special">,</span> <span class="identifier">elapsed</span><span class="special">);</span>
209
210        <span class="comment">// Reset our counts of bytes transferred</span>
211        <span class="identifier">read_bytes_</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
212        <span class="identifier">write_bytes_</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
213    <span class="special">}</span>
214
215<span class="keyword">public</span><span class="special">:</span>
216    <span class="identifier">rate_gauge</span><span class="special">()</span>
217        <span class="special">:</span> <span class="identifier">when_</span><span class="special">(</span><span class="identifier">clock_type</span><span class="special">::</span><span class="identifier">now</span><span class="special">())</span>
218    <span class="special">{</span>
219    <span class="special">}</span>
220
221    <span class="comment">/// Returns the current rate of reading in bytes per second</span>
222    <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span>
223    <span class="identifier">read_bytes_per_second</span><span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span>
224    <span class="special">{</span>
225        <span class="keyword">return</span> <span class="identifier">read_window_</span><span class="special">.</span><span class="identifier">value</span><span class="special">();</span>
226    <span class="special">}</span>
227
228    <span class="comment">/// Returns the current rate of writing in bytes per second</span>
229    <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span>
230    <span class="identifier">write_bytes_per_second</span><span class="special">()</span> <span class="keyword">const</span> <span class="keyword">noexcept</span>
231    <span class="special">{</span>
232        <span class="keyword">return</span> <span class="identifier">write_window_</span><span class="special">.</span><span class="identifier">value</span><span class="special">();</span>
233    <span class="special">}</span>
234<span class="special">};</span>
235</pre>
236<p>
237        To use our new policy we declare an instance of the stream, and then use
238        it with stream algorithms as usual. At any time, we can determine the current
239        read or write rates by calling into the policy.
240      </p>
241<pre class="programlisting"><span class="comment">// This stream will use our new rate_gauge policy</span>
242<span class="identifier">basic_stream</span><span class="special">&lt;</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">any_io_executor</span><span class="special">,</span> <span class="identifier">rate_gauge</span><span class="special">&gt;</span> <span class="identifier">stream</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">);</span>
243
244<span class="comment">//...</span>
245
246<span class="comment">// Print the current rates</span>
247<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span>
248    <span class="identifier">stream</span><span class="special">.</span><span class="identifier">rate_policy</span><span class="special">().</span><span class="identifier">read_bytes_per_second</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">" bytes/second read\n"</span> <span class="special">&lt;&lt;</span>
249    <span class="identifier">stream</span><span class="special">.</span><span class="identifier">rate_policy</span><span class="special">().</span><span class="identifier">write_bytes_per_second</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">" bytes/second written\n"</span><span class="special">;</span>
250</pre>
251</div>
252<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
253<td align="left"></td>
254<td align="right"><div class="copyright-footer">Copyright © 2016-2019 Vinnie
255      Falco<p>
256        Distributed under the Boost Software License, Version 1.0. (See accompanying
257        file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
258      </p>
259</div></td>
260</tr></table>
261<hr>
262<div class="spirit-nav">
263<a accesskey="p" href="timeouts.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../using_io.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="layered_streams.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
264</div>
265</body>
266</html>
267