转自 http://www.blogjava.net/canvas/articles/bandwidthlimiter.html

这里简单的讨论一下java设计网络程序中如何控制上传和下载速度,我们常见的FTP,HTTP,BT等协议都是TCP的,但是现在流行的utorrent却基于UDP实现了自己UTP协议(UDP+拥塞控制),不管使用什么协议,站在I/O的角度来说,限速的控制思路都是一样的。

思路很简单,如下:

1.假设下载或者上传速度上限是m (KB/s),那么发送一个固定的字节数据(假设是n字节)的时间花费是:n/m;
2.假设现在要发送n字节的数据,那么理论所需的时间应该是n/m,而在实际情况下,发送n字节的数据只花费了t秒,那么发送该发送线程就应该睡眠n/m-t秒,这样就基本实现了速度的控制。

代码以TCP为例
速度控制

 1 package com.actiontec.net.bandwidth;
 2 
 3 /**
 4  * 
 5  * @author Le
 6  * 
 7  */
 8 public class BandwidthLimiter {
 9 
10     /* KB */
11     private static Long KB = 1024l;
12 
13     /* The smallest count chunk length in bytes */
14     private static Long CHUNK_LENGTH = 1024l;
15 
16     /* How many bytes will be sent or receive */
17     private int bytesWillBeSentOrReceive = 0;
18 
19     /* When the last piece was sent or receive */
20     private long lastPieceSentOrReceiveTick = System.nanoTime();
21 
22     /* Default rate is 1024KB/s */
23     private int maxRate = 1024;
24 
25     /* Time cost for sending CHUNK_LENGTH bytes in nanoseconds */
26     private long timeCostPerChunk = (1000000000l * CHUNK_LENGTH)
27             / (this.maxRate * KB);
28 
29     /**
30      * Initialize a BandwidthLimiter object with a certain rate.
31      * 
32      * @param maxRate
33      *            the download or upload speed in KBytes
34      */
35     public BandwidthLimiter(int maxRate) {
36         this.setMaxRate(maxRate);
37     }
38 
39     /**
40      * Set the max upload or download rate in KB/s. maxRate must be grater than
41      * 0. If maxRate is zero, it means there is no bandwidth limit.
42      * 
43      * @param maxRate
44      *            If maxRate is zero, it means there is no bandwidth limit.
45      * @throws IllegalArgumentException
46      */
47     public synchronized void setMaxRate(int maxRate)
48             throws IllegalArgumentException {
49         if (maxRate < 0) {
50             throw new IllegalArgumentException("maxRate can not less than 0");
51         }
52         this.maxRate = maxRate < 0 ? 0 : maxRate;
53         if (maxRate == 0)
54             this.timeCostPerChunk = 0;
55         else
56             this.timeCostPerChunk = (1000000000l * CHUNK_LENGTH)
57                     / (this.maxRate * KB);
58     }
59 
60     /**
61      * Next 1 byte should do bandwidth limit.
62      */
63     public synchronized void limitNextBytes() {
64         this.limitNextBytes(1);
65     }
66 
67     /**
68      * Next len bytes should do bandwidth limit
69      * 
70      * @param len
71      */
72     public synchronized void limitNextBytes(int len) {
73         this.bytesWillBeSentOrReceive += len;
74 
75         /* We have sent CHUNK_LENGTH bytes */
76         while (this.bytesWillBeSentOrReceive > CHUNK_LENGTH) {
77             long nowTick = System.nanoTime();
78             long missedTime = this.timeCostPerChunk
79                     - (nowTick - this.lastPieceSentOrReceiveTick);
80             if (missedTime > 0) {
81                 try {
82                     Thread.sleep(missedTime / 1000000,
83                             (int) (missedTime % 1000000));
84                 } catch (InterruptedException e) {
85                     e.printStackTrace();
86                 }
87             }
88             this.bytesWillBeSentOrReceive -= CHUNK_LENGTH;
89             this.lastPieceSentOrReceiveTick = nowTick
90                     + (missedTime > 0 ? missedTime : 0);
91         }
92     }
93 }
94 
下载控制

 1 package com.actiontec.net.bandwidth;
 2 
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 
 6 /**
 7  * @author Le
 8  *
 9  */
10 public class DownloadLimiter extends InputStream {
11     private InputStream is = null;
12     private BandwidthLimiter bandwidthLimiter = null;
13     
14     public DownloadLimiter(InputStream is, BandwidthLimiter bandwidthLimiter)
15     {
16         this.is = is;
17         this.bandwidthLimiter = bandwidthLimiter;
18     }
19     @Override
20     public int read() throws IOException {
21         if(this.bandwidthLimiter != null)
22             this.bandwidthLimiter.limitNextBytes();
23         return this.is.read();
24     }
25 
26     public int read(byte b[], int off, int len) throws IOException
27     {
28         if (bandwidthLimiter != null)
29             bandwidthLimiter.limitNextBytes(len);
30         return this.is.read(b, off, len);
31     }
32 }
同样,上传控制
 1 package com.actiontec.net.bandwidth;
 2 
 3 import java.io.IOException;
 4 import java.io.OutputStream;
 5 
 6 /**
 7  * @author Le
 8  *
 9  */
10 public class UploadLimiter extends OutputStream {
11     private OutputStream os = null;
12     private BandwidthLimiter bandwidthLimiter = null;
13     
14     public UploadLimiter(OutputStream os, BandwidthLimiter bandwidthLimiter)
15     {
16         this.os = os;
17         this.bandwidthLimiter = bandwidthLimiter;
18     }
19     
20     @Override
21     public void write(int b) throws IOException {
22         if (bandwidthLimiter != null)
23             bandwidthLimiter.limitNextBytes();
24         this.os.write(b);
25     }
26     
27     public void write(byte[] b, int off, int len) throws IOException {
28         if (bandwidthLimiter != null)
29             bandwidthLimiter.limitNextBytes(len);
30         this.os.write(b, off, len);
31     }
32 
33 }
对于一个TCP socket
1 ServerSocket socket = new ServerSocket();
2 //其它初始化略
 1 //从socket中以一定的速率读数据
 2 //```java
 3 DownloadLimiter dl = new DownloadLimiter(socket.getInputStream(), new BandwidthLimiter(6250));
 4 is = new DataInputStream(dl);
 5 
 6 //读数据
 7 int len = is.readInt();
 8 ByteBuffer buffer = ByteBuffer.allocate(4 + len);
 9 buffer.putInt(len);
10 is.readFully(buffer.array(), 4, buffer.remaining());
11 //```
12 
13 //以一定的速率写数据到socket
14 //```java
15 UploadLimiter ul = new UploadLimiter(socket.getOutputStream(), new BandwidthLimiter(6250));
16 ul.write();
17 //```
 
转载自:https://blog.csdn.net/shulai123/article/details/62215908/   
 
亲测有效
 
 

Java程序如何限速(控制下载和上传速度)的更多相关文章

  1. 重新想象 Windows 8.1 Store Apps (91) - 后台任务的新特性: 下载和上传的新特性, 程序启动前预下载网络资源, 后台任务的其它新特性

    [源码下载] 重新想象 Windows 8.1 Store Apps (91) - 后台任务的新特性: 下载和上传的新特性, 程序启动前预下载网络资源, 后台任务的其它新特性 作者:webabcd 介 ...

  2. 重新想象 Windows 8 Store Apps (66) - 后台任务: 下载和上传

    [源码下载] 重新想象 Windows 8 Store Apps (66) - 后台任务: 下载和上传 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 后台任务 后台 ...

  3. github下载和上传项目

    git下载和上传项目 下载: git clone +地址 上传: 1.git init 在当前项目的目录中生成本地的git管理(多一个.git文件夹,为隐藏文件) 2.git add .(注意最后面有 ...

  4. Java初学者作业——编写JAVA程序,在控制台中输入六位员工的姓名,通过随机点名方式,输出当选组长的员工姓名。

    返回本章节 返回作业目录 需求说明: 编写JAVA程序,在控制台中输入六位员工的姓名,通过随机点名方式,输出当选组长的员工姓名. 实现思路: (1)定义字符串类型的数组names,长度为6,用于存储六 ...

  5. Java初学者作业——编写Java程序,在控制台中输入一个数字,要求定义方法实现找出能够整除该数字的所有数字。

    返回本章节 返回作业目录 需求说明: 编写Java程序,在控制台中输入一个数字,要求定义方法实现找出能够整除该数字的所有数字. 实现思路: 定义方法findNums(),用于实现查找所有能够整除指定数 ...

  6. Java初学者作业——编写 Java 程序,在控制台中输入日期,计算该日期是对应年份的第几天。

    返回本章节 返回作业目录 需求说明: 编写 Java 程序,在控制台中输入日期,计算该日期是对应年份的第几天. 实现思路: (1)声明变量 year.month和 date,用于存储日期中的年.月.日 ...

  7. Ubuntu 16.04通过Trickle限制某个软件的下载/上传速度

    在Linux下没有Windows使用360那样去限制某个软件的速度. 但是通过Trickle可以设置某个软件的网速,但是前提是通过Trickle命令连带启动这个软件才可以,不能中途去设置. 比如现在很 ...

  8. window系统使用tftp下载和上传文件

    安装tftp32服务器 首先需要安装tftp服务器:tftpd32 , 下载以后的目录如下: tftp使用帮助 命令提示符(cmd): 直接运行tftpd32.exe tftp命令的用法: 关于tft ...

  9. selenium和AutoIt工具辅助下载和上传

    上传 根据AutoIt Windows Info 所识别到的控件信息打开SciTE Script Editor编辑器,编写脚本. ;ControlFocus("title",&qu ...

随机推荐

  1. 使用原生node.js搭建HTTP服务器,支持MP4视频、图片传输,支持下载rar文件

    前言 如何安装node.js,如何搭建一个简易的http服务器我这里就不再赘述了,不懂的同学可以先去学习一下.当然了,我写的也就属于简易版的增强版,大家有什么高见的欢迎提出,然后进入正题. 目录结构 ...

  2. curl命令用法

    curl命令是一个功能强大的网络工具,它能够通过http.ftp等方式下载文件,也能够上传文件,同时支持HTTPS等众多协议,还支持POST.cookies.认证.从指定偏移处下载部分文件.用户代理字 ...

  3. Python脚本带-的参数脚本

    一.故事背景 由于先前的工作内容是做后台开发,对于脚本写的很少: 昨天参加面试遇到一道面试题,写一个python脚本: 通过脚本的后面的参数选项获取参数选项后面的字符串进行处理: 问题没记错的话大概是 ...

  4. Windows 下的快捷键

    电脑快捷键小技巧window健 + r   →  msconfig       查看电脑的开机启动项window健 + r   →  notepad        无标题的记事本window健 + r ...

  5. 第十五章、Python多线程之信号量和GIL

    目录 第十五章.Python多线程之信号量和GIL 1. 信号量(Semaphore) 2. GIL 说明: 第十五章.Python多线程之信号量和GIL 1. 信号量(Semaphore) 信号量用 ...

  6. xampp下载和使用

    XAMPP 下载地址: XAMPP HTML存放目录,也就是根目录,可以在这个目录进行添加HTML文件和PHP文件. C:\xampp\htdocs 访问web,localhost:80或者直接访问l ...

  7. Hive-ha (十三)

    hive-high Avaliable ​ hive的搭建方式有三种,分别是 ​ 1.Local/Embedded Metastore Database (Derby) ​ 2.Remote Meta ...

  8. web开发中的支付宝支付和微信支付

    https://www.jianshu.com/p/155757d2b9eb <!-- wxPay --SDK--> <script src="https://res.wx ...

  9. Android异常与性能优化相关面试问题-ANR异常面试问题详解

    什么是ANR? Application Not Responding 造成ANR的主要原因: 应用程序的响应性是由ActivityManager和WindowManager系统服务监视的,当监视到在A ...

  10. BZOJ2118 墨墨的等式[同余类最短路]

    声明:关于这题的$O(mn)$尚且未深入理解,虽然之前有跟这位神仙聊过做法但并没太懂.. $O(mn\log m)$同余最短路做法: 首先不妨抽出最小的$a_i=m$,那么剩余的$a$如果可以表示出$ ...