2011-06-07 110 views
5

我想以编程方式限制Java中的上传或下载操作。我将承担所有我需要做的就是做检查上载有多快,并插入相应Thread.sleep()像这样:限制Java的上传速度?

while (file.hasMoreLines()) { 
    String line = file.readLine(); 
    for (int i = 0; i < line.length(); i+=128) { 
     outputStream.writeBytes(line.substr(i, i+128).getBytes()); 
     if (isHittingLimit()) 
      Thread.sleep(500); 
    } 
} 

请问上面的代码工作?如果没有,有没有更好的方法来做到这一点?有没有描述理论的教程?

+0

这可能会减慢上/下载率。尽管取决于在每次迭代中发送的数据量以及睡眠周期的长度,但可能难以精确限制(即,连接速度将改变但不清楚多少)。为了更好地进行调整,理论上你会希望减少在每次迭代中发送的数据量(例如从一行到一个字符)以及在限制被打时花费的时间。这应该会导致更频繁和更精细的调整...不张贴为答案,因为我没有教程,并没有验证它。 – gnomed 2011-06-07 20:51:18

+0

另外:使用Reader也不是一个好主意,也不是逐行读取,因为您基本上是将字节(UTF-8等)中的数据解码为字符,然后重新编码,取出一些字节,放下其他字节。而是从InputStream中读取一定数量的字节,发送这些字节,并避免在这里不需要的解码/编码。 – StaxMan 2011-06-07 23:49:20

回答

6

Token Bucket Algorithm是一种限制上传或下载带宽的方法。 您应该阅读this article:它解释了这种算法的使用。

使用Guava RateLimiter

// rate = 512 permits per second or 512 bytes per second in this case 
final RateLimiter rateLimiter = RateLimiter.create(512.0); 

while (file.hasMoreLines()) { 
    String line = file.readLine(); 
    for (int i = 0; i < line.length(); i+=128) { 
     byte[] bytes = line.substr(i, i+128).getBytes(); 
     rateLimiter.acquire(bytes.length); 
     outputStream.writeBytes(bytes); 
    } 
} 

如番石榴文档解释说: 需要注意的是许可证的数量要求从不影响请求本身(调用获取(1)与节流很重要调用获取(1000)将导致完全相同的调节,如果有的话),但它会影响下一个请求的调节。也就是说,如果一个昂贵的任务到达一个空闲的RateLimiter,它将被立即授予,但是它是下一个请求会经历额外的限制,从而支付昂贵任务的成本。

+0

https://github.com/bbeck/token-bucket实施 – kervin 2015-08-09 16:48:09

0

你需要一些方法让isHittingLimit知道有多少字节已经传输了多长时间。有一个有趣的方法in this thread,你可能会适应。

1

这是一个古老的职位,但这个怎么样:

import com.google.common.util.concurrent.RateLimiter; 
import java.io.IOException; 
import java.io.OutputStream; 

public final class ThrottledOutputStream extends OutputStream { 
    private final OutputStream out; 
    private final RateLimiter rateLimiter; 

    public ThrottledOutputStream(OutputStream out, double bytesPerSecond) { 
     this.out = out; 
     this.rateLimiter = RateLimiter.create(bytesPerSecond); 
    } 

    public void setRate(double bytesPerSecond) { 
     rateLimiter.setRate(bytesPerSecond); 
    } 

    @Override 
    public void write(int b) throws IOException { 
     rateLimiter.acquire(); 
     out.write(b); 
    } 

    @Override 
    public void write(byte[] b) throws IOException { 
     rateLimiter.acquire(b.length); 
     out.write(b); 
    } 

    @Override 
    public void write(byte[] b, int off, int len) throws IOException { 
     rateLimiter.acquire(len); 
     out.write(b, off, len); 
    } 

    @Override 
    public void flush() throws IOException { 
     out.flush(); 
    } 

    @Override 
    public void close() throws IOException { 
     out.close(); 
    } 
} 

取决于番石榴,特别是RateLimiter。