C#中的带宽限制我正在开发一个在后台发送源源不断的数据的程序,我希望用户设置上传和下载限制的上限。我已经阅读了令牌桶和漏桶的算法,后者似乎符合描述,因为这不是最大化网络带宽的问题,而是尽可能不引人注目的问题。但是,我不确定如何实现这一点。一种自然的方法是扩展抽象Stream类以简化现有流的扩展,但这是否需要额外的线程参与以在接收数据时发送数据(漏桶)?对其他实现的任何提示将不胜感激。此外,虽然我可以修改我的程序接收的数据量,但带宽限制在C#级别的效果如何?计算机是否仍会接收数据并保存,从而有效地取消节流效果,或者它会等到我要求接收更多数据时再接收吗?编辑:我对限制传入和传出数据感兴趣,我无法控制流程的另一端。请参阅有关ThrottledStream类的文章。它应该适合您的需要。我想出了arul提到的ThrottledStream类的不同实现。我的版本使用间隔为1s的WaitHandle和Timer:publicThrottledStream(StreamparentStream,intmaxBytesPerSecond=int.MaxValue){父母=父母流;处理=0;resettimer=newSystem.Timers.Timer();重置定时器.Interval=1000;resettimer.Elapsed+=resettimer_Elapsed;重置定时器。开始();}protectedvoidThrottle(intbytes){try{processed+=bytes;如果(已处理>=maxBytesPerSecond)wh.WaitOne();}catch{}}privatevoidresettimer_Elapsed(objectsender,ElapsedEventArgse){processed=0;wh.Set();每当带宽限制超过线程时,线程就会休眠直到下一秒开始。无需计算最佳睡眠时间。全局实施:publicclassThrottledStream:Stream{#regionPropertiesprivateintmaxBytesPerSecond;//////每秒允许的字节数///publicintMaxBytesPerSecond{get{returnmaxBytesPerSecond;}set{if(value0");maxBytesPerSecond=value;}}#endregion#regionPrivateMembersprivateintprocessed;System.Timers.Timerresettimer;AutoResetEventwh=newAutoResetEvent(true);privateStreamparent;#endregion/////创建一个带数据带宽上限的新流/////////publicThrottledStream(StreamparentStream,intmaxBytesPerSecond=int.MaxValue){MaxBytesPerSecond=maxBytesPerSecond;parent=parentStream;processed=0;resettimer=newSystem.Timers.Timer();resettimer.Interval=1000;resettimer.Elapsed+=resettimer_Elapsed;resettimer.Start();}protectedvoidThrottle(intbytes){try{processed+=bytes;if(processed>=maxBytesPerSecond)wh.WaitOne();}catch{}}privatevoidresettimer_Elapsed(objectsender,ElapsedEventArgse){processed=0;wh.Set();}#regionStream-OverridespublicoverridevoidClose(){resettimer.Stop();resettimer.Close();基地.关闭();}protectedoverridevoidDispose(booldisposing){resettimer.Dispose();base.Dispose(处置);}publicoverrideboolCanRead{get{returnparent.CanRead;}}publicoverrideboolCanSeek{get{returnparent.CanSeek;}}publicoverrideboolCanWrite{get{returnparent.CanWrite;}}publicoverridevoidFlush(){parent.Flush();}publicoverridelongLength{get{returnparent.Length;}}publicoverridelongPosition{get{returnparent.Position;}set{parent.Position=value;}}publicoverrideintRead(byte[]buffer,intoffset,intcount){Throttle(count);返回parent.Read(缓冲区,偏移量,计数);}publicoverridelongSeek(longoffset,SeekOriginorigin){returnparent.Seek(offset,origin);}publicoverridevoidSetLength(longvalue){parent.SetL长度(值);}publicoverridevoidWrite(byte[]buffer,intoffset,intcount){Throttle(count);parent.Write(缓冲区,偏移量,计数);}#endregion}基于@0xDEADBEEF的解决方案,我基于Rx调度程序创建了以下(可测试的)解决方案:publicclassThrottledStream:Stream{privatereadonlyStreamparent;私有只读intmaxBytesPerSecond;私有只读IScheduler调度程序;私人只读IStopwatch秒表;私人长加工;publicThrottledStream(Streamparent,intmaxBytesPerSecond,ISchedulerscheduler){this.maxBytesPerSecond=maxBytesPerSecond;this.parent=parent;this.scheduler=调度程序;秒表=scheduler.StartStopwatch();处理=0;}publicThrottledStream(Streamparent,intmaxBytesPerSecond):this(parent,maxBytesPerSecond,Scheduler.Immediate){}protectedvoidThrottle(intbytes){processed+=bytes;vartargetTime=TimeSpan.FromSeconds((double)processed/maxBytesPerSecond);varactualTime=stopwatch.Elapsed;变种睡眠=目标时间-实际时间;if(sleep>TimeSpan.Zero){using(varwaitHandle=newAutoResetEvent(initialState:false)){scheduler.Sleep(sleep).GetAwaiter().OnCompleted(()=>waitHandle.Set());waitHandle.WaitOne();}}}publicoverrideboolCanRead{get{returnparent.CanRead;}}publicoverrideboolCanSeek{get{returnparent.CanSeek;}}publicoverrideboolCanWrite{get{returnparent.CanWrite;}}publicoverridevoidFlush(){parent.Flush();}publicoverridelongLength{get{returnparent.Length;}}publicoverridelongPosition{get{returnparent.Position;}set{parent.Position=value;}}publicoverrideintRead(byte[]buffer,intoffset,intcount){varread=parent.Read(buffer,offset,count);油门(读);返回阅读;}publicoverridelongSeek(longoffset,SeekOriginorigin){returnparent.Seek(offset,origin);}publicoverridevoidSetLength(longvalue){parent.SetLength(value);}publicoverridevoidWrite(byte[]buffer,intoffset,intcount){Throttle(count);parent.Write(缓冲区,偏移量,计数);}}和一些只需要几毫秒的测试:以上是C#学习教程:BandwidthinC#有限分享的所有内容,如果对你有用,需要进一步了解C#学习教程,我希望大家多多关注——[TestMethod]publicvoidShouldThrottleReading(){varcontent=Enumerable.Range(0,1024*1024).Select(_=>(byte)'a').ToArray();varscheduler=newTestScheduler();varsource=newThrottledStream(newMemoryStream(content),content.Length/8,scheduler);vartarget=newMemoryStream();vart=source.CopyToAsync(target);t.Wait(10).Should().BeFalse();scheduler.AdvanceTo(TimeSpan.FromSeconds(4).Ticks);t.等待(10)。应该().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]publicvoidShouldThrottleWriting(){varcontent=Enumerable.Range(0,1024*1024).Select(_=>(byte)'a').ToArray();varscheduler=新的TestS调度程序();varsource=newMemoryStream(内容);vartarget=newThrottledStream(newMemoryStream(),content.Length/8,scheduler);vart=来源。CopyToAsync(目标);吨。等待(10)。应该().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();}网络收藏不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
