在计算机网络中,限流就是控制网络接口发送或接收请求的速率,它可防止DOs攻击和限制Web爬虫。
也称流量控制。是指系统在面临高并发或者大流量请求的情况下,限制新的请求对系统的访问,从而保证系统的访问。
常见限流算法:
一、固定窗口算法
二、滑动窗口限流算法
三、漏桶算法
四、令牌桶算法
下面是内存固定窗口限流算法的简单实现。
(1)使用Hashtable保存每个请求来源。
(2)定义模型rateRule作为限流规则。
(3)计算TcpClient中的RemoteEndPoint属性的MD5值作为哈希表的key,value值包括访问次数、过期时间,至多访问次数。
(4) 每一个tcpClient都经过checkRule函数,超限后直接关闭连接,并返回true否则返回false。
(5) 首先提取请求的RemoteEndPoint属性并计算其MD5值作为限流目标,然后根据限流目标到hashTable中查找限流参数。如果不存在,则添加一个记录,访问次数是1,过期时间是当前时间+限流时间长度。如果存在则检查是否过期,如果过期,则参数重置。如果未过期,则访问次数+1并检查访问次数是否超限,超限则直接关闭,返回true,否则返回false。
#region 限流设置
/// <summary>
/// 限流哈希表
/// </summary>
static public Hashtable rateLimiterTable { get; set; } = new Hashtable(20);
/// <summary>
/// 限流规则
/// </summary>
public class rateRule
{
/// <summary>
///
/// </summary>
/// <param name="_timeOffTotal">时间长度内最多timeOffTotal次</param>
/// <param name="timeSpan">过期时间长度</param>
public rateRule(string _name, int _timeOffTotal, TimeSpan _timeSpan)
{
name = _name;
timeOffTotal = _timeOffTotal;
timespace = _timeSpan;
timeOff = DateTime.Now.Add(_timeSpan);
}
public string name { get; set; }
/// <summary>
/// 访问次数
/// </summary>
public int sum { get; set; } = 1;
public TimeSpan timespace { get; set; }
/// <summary>
/// 过期时间
/// </summary>
public DateTime timeOff { get; set; }
/// <summary>
/// timeOff时间内最多timeOffTotal次
/// </summary>
public int timeOffTotal { get; set; }
}
#region 将远程终结点格式化为以IP地址和端口号为表示形式的网络端点
/// <summary>
/// 将远程终结点格式化为以IP地址和端口号为表示形式的网络端点
/// </summary>
/// <param name="RemoteEndPoint">远程终结点字符串</param>
/// <returns></returns>
public IPEndPoint IpAndPortFormat(EndPoint RemoteEndPoint)
{
try
{
IPAddress ipAdes = IPAddress.Parse("0.0.0.0");
int port = 0;
string[] array_ipAndPort = RemoteEndPoint.ToString().Split(':');
if (array_ipAndPort.Length == 2)
{
IPAddress.TryParse(array_ipAndPort[0], out ipAdes);
int.TryParse(array_ipAndPort[1], out port);
}
return new IPEndPoint(ipAdes, port);
}
catch (Exception ex)
{
Tools.Instance.WriteError(ex);
}
return new IPEndPoint(1, 0);
}
#endregion
/// <summary>
/// 限流监测
/// </summary>
/// <param name="tc"></param>
/// <returns></returns>
public bool checkRule(TcpClient tc)
{
bool close = false;
IPEndPoint iPEndPoint = IpAndPortFormat(tc.Client.RemoteEndPoint);
string ip = iPEndPoint.Address.ToString();
List<rateRule> rules = null;
lock (rateLimiterTable.SyncRoot)
{
rules = (List<rateRule>)rateLimiterTable[ip];
}
if (rules == null)
{
rules = new List<rateRule>();
rules.Add(new rateRule("[1分钟内至多3次]", 3, new TimeSpan(0, 1, 0)));
rules.Add(new rateRule("[5分钟内至多10次]", 10, new TimeSpan(0, 5, 0)));
rules.Add(new rateRule("[10分钟内至多15次]", 15, new TimeSpan(0, 10, 0)));
rules.Add(new rateRule("[20分钟内至多20次]", 20, new TimeSpan(0, 20, 0)));
rules.Add(new rateRule("[1小时内至多30次]", 30, new TimeSpan(1, 0, 0)));
rules.Add(new rateRule("[1.5小时内至多60次]", 60, new TimeSpan(1, 30, 0)));
rateLimiterTable.Add(ip, rules);
}
else
{
foreach (var rule in rules)
{
if (DateTime.Now < rule.timeOff)
{
//在限制时间内
if (rule.sum > rule.timeOffTotal)
{
//超了
if (close == false)
{
tc.Close();
close = true;
}
//inout.Common.Tools.Instance.WriteDebugLog($"{ip},规则:{rule.name}超期");
}
else
{
//未超
}
rule.sum++;
}
else
{
//不在限制时间内了,恢复
//inout.Common.Tools.Instance.WriteDebugLog($"{ip},规则{rule.name}恢复,次数达到{rule.sum}");
rule.sum = 1;
rule.timeOff = DateTime.Now.Add(rule.timespace);
}
}
}
return close;
}
应用:
TcpListener tcpListener = new TcpListener(ipAndPort);
...
TcpClient tc = tcpListener.AcceptTcpClient();
if (Tools.Instance.checkRule(tc)==false)
{
...
}
限流效果:
部署在服务器中,确实达到了一定的限流效果。可以叠加任意数量,任意时间长度的限流规则,每个请求经过重重考验方能到达目的地,把访问太频繁的一切请求直接close。
2023/8/5 22:00:06:43.136.114.252,规则[1分钟内至多3次]恢复,次数达到2
2023/8/5 22:00:06:43.136.114.252,规则:[1小时内至多30次]超期,次数达到61
2023/8/5 22:00:06:43.136.114.252,规则:[2小时内至多50次]超期,次数达到72
2023/8/5 22:00:08:103.91.209.30,规则:[5分钟内至多10次]超期,次数达到13
2023/8/5 22:00:08:103.91.209.30,规则:[10分钟内至多15次]超期,次数达到39
2023/8/5 22:00:08:103.91.209.30,规则:[1小时内至多30次]超期,次数达到41
2023/8/5 22:00:08:103.91.209.30,规则:[1.5小时内至多40次]超期,次数达到50
2023/8/5 22:00:08:103.91.209.30,规则:[2小时内至多50次]超期,次数达到292
2023/8/5 22:00:23:103.91.209.30,规则:[5分钟内至多10次]超期,次数达到14
2023/8/5 22:00:23:103.91.209.30,规则:[10分钟内至多15次]超期,次数达到40
2023/8/5 22:00:23:103.91.209.30,规则:[1小时内至多30次]超期,次数达到42
2023/8/5 22:00:23:103.91.209.30,规则:[1.5小时内至多40次]超期,次数达到51
2023/8/5 22:00:23:103.91.209.30,规则:[2小时内至多50次]超期,次数达到293
2023/8/5 22:00:38:103.91.209.30,规则:[1分钟内至多3次]超期,次数达到4
2023/8/5 22:00:38:103.91.209.30,规则:[5分钟内至多10次]超期,次数达到15
2023/8/5 22:00:38:103.91.209.30,规则[10分钟内至多15次]恢复,次数达到41
2023/8/5 22:00:38:103.91.209.30,规则:[1小时内至多30次]超期,次数达到43
2023/8/5 22:00:38:103.91.209.30,规则:[1.5小时内至多40次]超期,次数达到52
2023/8/5 22:00:38:103.91.209.30,规则:[2小时内至多50次]超期,次数达到294
2023/8/5 22:00:53:103.91.209.30,规则[1分钟内至多3次]恢复,次数达到5
2023/8/5 22:00:53:103.91.209.30,规则:[5分钟内至多10次]超期,次数达到16
2023/8/5 22:00:53:103.91.209.30,规则:[1小时内至多30次]超期,次数达到44
2023/8/5 22:00:53:103.91.209.30,规则:[1.5小时内至多40次]超期,次数达到53
2023/8/5 22:00:53:103.91.209.30,规则:[2小时内至多50次]超期,次数达到295
2023/8/5 22:01:03:43.136.114.252,规则:[1小时内至多30次]超期,次数达到62
我已将代码上传,下载码是:D0B001B435
下载码是啥?如何下载=》点击查看