限制Java上传速度?

5

我希望能够在Java中以编程方式限制上传或下载操作。我认为我所需要做的就是检查上传速度,然后相应地插入Thread.sleep(),如下所示:

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);
    }
}

上述代码是否可行?如果不行,有更好的方法吗?是否有描述该理论的教程?


那可能会减慢上传/下载速率。虽然这取决于每次迭代发送的数据量和休眠时间的长度,但很难精确限制(即连接速度将发生变化,但不清楚变化幅度)。为了使其更加精细调整,在理论上,您需要减少每次迭代发送的数据量(例如从一行到一个字符)以及达到限制时花费的休息时间。这应该会导致更频繁和更精细的调整...我没有教程也没有验证,所以不作为答案发布。 - gnomed
另外,使用Reader或按行读取数据并不是一个好主意,因为你基本上是将字节(UTF-8或类似的)解码为字符,然后重新编码,取一些字节,丢掉其他字节。相反,从InputStream中读取特定数量的字节,发送这些字节,并避免不必要的解码/编码。 - StaxMan
3个回答

7

令牌桶算法是一种限制上传或下载带宽的方法。你应该阅读这篇文章:它解释了这个算法的用途。

使用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);
    }
}

如Guava文档所述: 需要注意的是,请求的许可证数量从不影响请求本身的限流(如果调用acquire(1)和acquire(1000),则无论如何都将导致完全相同的限流效果),但它会影响下一个请求的限流。也就是说,如果一个昂贵的任务到达了一个空闲的RateLimiter,则会立即被授予,但下一个请求将经历额外的限流,因此要为昂贵任务的成本付费。


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();
    }
}

依赖于Guava,具体来说是RateLimiter。

0

您需要一些方法让isHittingLimit知道已经传输了多少字节以及花费了多长时间。这里有一个有趣的方法在这个线程中,您可以尝试适应一下。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接