C# 中的带宽限制

2024-03-09

我正在开发一个程序,该程序在后台不断发送数据流,我希望允许用户设置上传和下载限制的上限。

我已经阅读了令牌桶 http://en.wikipedia.org/wiki/Token_bucket and 漏桶 http://en.wikipedia.org/wiki/Leaky_bucket算法,似乎后者似乎符合描述,因为这不是最大化网络带宽的问题,而是尽可能不引人注目的问题。

然而,我有点不确定如何实现这一点。一种自然的方法是扩展抽象 Stream 类,以简化现有流量的扩展,但这是否不需要额外的线程来发送数据,同时接收数据(漏桶)?任何有关执行相同操作的其他实现的提示将不胜感激。

另外,虽然我可以修改程序接收的数据量,但带宽限制在 C# 级别的效果如何?计算机是否仍然会接收数据并简单地保存它,从而有效地取消限制效果,还是会等到我要求接收更多数据?

编辑:我对限制传入和传出数据感兴趣,我无法控制流的另一端。


基于 @0xDEADBEEF 的解决方案,我创建了以下基于 Rx 调度程序的(可测试的)解决方案:

public class ThrottledStream : Stream
{
    private readonly Stream parent;
    private readonly int maxBytesPerSecond;
    private readonly IScheduler scheduler;
    private readonly IStopwatch stopwatch;

    private long processed;

    public ThrottledStream(Stream parent, int maxBytesPerSecond, IScheduler scheduler)
    {
        this.maxBytesPerSecond = maxBytesPerSecond;
        this.parent = parent;
        this.scheduler = scheduler;
        stopwatch = scheduler.StartStopwatch();
        processed = 0;
    }

    public ThrottledStream(Stream parent, int maxBytesPerSecond)
        : this (parent, maxBytesPerSecond, Scheduler.Immediate)
    {
    }

    protected void Throttle(int bytes)
    {
        processed += bytes;
        var targetTime = TimeSpan.FromSeconds((double)processed / maxBytesPerSecond);
        var actualTime = stopwatch.Elapsed;
        var sleep = targetTime - actualTime;
        if (sleep > TimeSpan.Zero)
        {
            using (var waitHandle = new AutoResetEvent(initialState: false))
            {
                scheduler.Sleep(sleep).GetAwaiter().OnCompleted(() => waitHandle.Set());
                waitHandle.WaitOne();
            }
        }
    }

    public override bool CanRead
    {
        get { return parent.CanRead; }
    }

    public override bool CanSeek
    {
        get { return parent.CanSeek; }
    }

    public override bool CanWrite
    {
        get { return parent.CanWrite; }
    }

    public override void Flush()
    {
        parent.Flush();
    }

    public override long Length
    {
        get { return parent.Length; }
    }

    public override long Position
    {
        get
        {
            return parent.Position;
        }
        set
        {
            parent.Position = value;
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        var read = parent.Read(buffer, offset, count);
        Throttle(read);
        return read;
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        return parent.Seek(offset, origin);
    }

    public override void SetLength(long value)
    {
        parent.SetLength(value);
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        Throttle(count);
        parent.Write(buffer, offset, count);
    }
}

一些测试只需要几毫秒:

[TestMethod]
public void ShouldThrottleReading()
{
    var content = Enumerable
        .Range(0, 1024 * 1024)
        .Select(_ => (byte)'a')
        .ToArray();
    var scheduler = new TestScheduler();
    var source = new ThrottledStream(new MemoryStream(content), content.Length / 8, scheduler);
    var target = new MemoryStream();

    var t = source.CopyToAsync(target);

    t.Wait(10).Should().BeFalse();
    scheduler.AdvanceTo(TimeSpan.FromSeconds(4).Ticks);
    t.Wait(10).Should().BeFalse();
    scheduler.AdvanceTo(TimeSpan.FromSeconds(8).Ticks - 1);
    t.Wait(10).Should().BeFalse();
    scheduler.AdvanceTo(TimeSpan.FromSeconds(8).Ticks);
    t.Wait(10).Should().BeTrue();
}

[TestMethod]
public void ShouldThrottleWriting()
{
    var content = Enumerable
        .Range(0, 1024 * 1024)
        .Select(_ => (byte)'a')
        .ToArray();
    var scheduler = new TestScheduler();
    var source = new MemoryStream(content);
    var target = new ThrottledStream(new MemoryStream(), content.Length / 8, scheduler);

    var t = source.CopyToAsync(target);

    t.Wait(10).Should().BeFalse();
    scheduler.AdvanceTo(TimeSpan.FromSeconds(4).Ticks);
    t.Wait(10).Should().BeFalse();
    scheduler.AdvanceTo(TimeSpan.FromSeconds(8).Ticks - 1);
    t.Wait(10).Should().BeFalse();
    scheduler.AdvanceTo(TimeSpan.FromSeconds(8).Ticks);
    t.Wait(10).Should().BeTrue();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# 中的带宽限制 的相关文章

随机推荐

  • 如何在 scala 中按 Ordered 参数化 Int

    我有一个具有参数化类型的类 我想对其进行比较运算符 我认为我需要使用 Ordered 特征来实现这一点 但编译器不喜欢我使用它 假设我有以下课程 class Test T lt Ordered T def someOp t T if t l
  • 仅当在构建服务器上运行时单元测试才会失败

    为了帮助单元测试 我们已经完成了DateTime委托中的类 以便DateTime Now可以在单元测试中被覆盖 public static class SystemTime region Static Fields public stati
  • 如何检测我的 Android 应用程序中的广告拦截器?

    有什么方法可以检测广告拦截器何时在应用程序中运行 我想在我的应用程序中检测用户是否使用任何应用程序来阻止应用程序中的广告 如果是 那么我想向用户显示弹出窗口 要求他在使用应用程序时禁用广告拦截器 Android 操作系统没有提供官方方法来以
  • Typescript/babel 导入导致“_1.default 不是函数”

    我正在尝试使用https github com timmywil panzoom https github com timmywil panzoom来自使用 webpack 和 babel 编译的 typescript 项目 问题是打字稿方
  • 自定义树视图

    有没有办法自定义 winform 树视图以获得类似的东西 目的是通过父项目使用一种颜色并定义一个三角形而不是 图标来开发项目 Use TreeViewDrawMode OwnerDrawText所以缩进将由TreeView 除此之外 你应该
  • ::ng-deep 将被弃用 - 有其他选择吗?

    医生说 阴影穿透后代组合器已被弃用 并且主要浏览器和工具正在删除支持 因此 我们计划放弃对 Angular 的支持 对于 deep gt gt gt 和 ng deep 的所有 3 个 在那之前 应该首选 ng deep 以获得与工具更广泛
  • 在 JBoss 上部署 Hibernate 应用程序时出错 - 找不到适用于 jdbc 的驱动程序

    我有一个 Spring Hibernate Web 应用程序 目前在 Tomcat 上运行良好 我正尝试将其部署到 JBoss 7 1 AS 应用程序全部正确启动 但如果我设置 Hibernate Persistence 设置来创建表 则会
  • 如何使用冒号解组 XML 属性?

    我正在使用的一些 SVG XML 文件的属性名称中包含破折号和冒号 例如
  • 如何使用 jasmine 测试 $window.open

    这是我的功能 scope buildForm function majorObjectId name window open FormBuilder Index scope currentAppId form majorObjectId n
  • 如何在 perl 中创建多维数组?

    我这样创建一个多维数组 usr bin perl use warnings use strict my a1 1 2 my a2 a1 3 但事实证明我仍然得到一个一维数组 Perl 中正确的方法是什么 你得到一个一维数组 因为数组 a1在
  • 让 Collections.binarySearch() 与 CompareToIgnoreCase 一起使用?

    因此 我正在一个巨大的 ArrayList 中搜索特定的 String 值 但如果我正在查找的 String 与我传递给的 String 相等 不区分大小写 我需要 Collections binarySearch 返回一个 gt 0 的值
  • 如何使用 jQuery 获取文本输入的所有值?

    我有一个表 其中有一列预先填充的文本输入 table tr td td td td tr table
  • 如何将 zip 文件上传到 azure blob,然后在那里解压缩 [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我有很多 zip 文件 其中只有几个文件夹和 50 多个文件 如何将这些 zip 文件上传到 azure blob 然后在那里解压缩 将服务
  • mvc c# html.dropdownlist 和 viewbag

    所以我有以下 伪代码 string selectedvalud C List
  • 如何在node.js模块中实现继承?

    我正在编写 Nodejs 应用程序 它基于expressjs 我对在 Nodejs 模块中进行继承感到困惑 我想做的是创建一个模型基类 比方说 my model js module exports function my model my
  • 在 C# 中提取 .cab 文件

    我正在开发一个 C 应用程序 我需要提取一个 cab 文件 我找不到在 C 中执行此操作的库 由于许可问题 我无法使用 Microsoft Deployment Compression Cab dll I found this https
  • 联系表格 7 至 WordPress 用户数据库

    我编写了以下函数 以便在发送联系表单时将其添加到用户数据库字段中 问题是它发送了最终电子邮件 但没有向数据库输入任何内容 因此我一定在某个地方出现错误 任何帮助将不胜感激 add action wpcf7 before send mail
  • 如何向 Spring Security 用户详细信息添加其他详细信息

    我想向用户详细信息添加其他信息 例如用户的 IP 地址 有什么办法可以实现这一点吗 我尝试创建一个新的 CustomSpringUser 类 但问题是如何从 Authentication 对象获取此信息 有没有其他方法来存储经过身份验证的用
  • NSDateFormatter 毫秒错误

    我想创建一个 NSDateFormatter 来解析像这样的日期 2014 05 13 23 31 41 374577 所以 NSDateFormatter formatter NSDateFormatter alloc init form
  • C# 中的带宽限制

    我正在开发一个程序 该程序在后台不断发送数据流 我希望允许用户设置上传和下载限制的上限 我已经阅读了令牌桶 http en wikipedia org wiki Token bucket and 漏桶 http en wikipedia o