【问题标题】:Limiting upload speed on Java?限制Java的上传速度?
【发布时间】:2011-09-10 09:56:34
【问题描述】:

我想以编程方式限制 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);
    }
}

上面的代码会起作用吗?如果没有,有没有更好的方法来做到这一点?有没有介绍理论的教程?

【问题讨论】:

  • 这可能会减慢上传/下载速度。虽然取决于每次迭代发送多少数据,以及睡眠期的长度,但可能很难准确限制(即连接速度会改变,但不清楚多少)。为了使其更精细,理论上您会希望减少每次迭代发送的数据量(例如从一行到一个字符)以及达到限制时花费的休息时间。这应该会导致更频繁和更精细的调整......因为我没有教程并且没有验证它,所以不发布作为答案。
  • 另外:使用 Reader 或逐行读取都不是一个好主意,因为您基本上是将数据从字节(UTF-8 等)解码为字符,只是为了重新编码,采取一些字节,丢弃其他。相反,从 InputStream 读取一定数量的字节,发送这些字节,并避免此处不需要的解码/编码。

标签: java network-programming theory bandwidth-throttling


【解决方案1】:

您需要某种方式让 isHittingLimit 知道在多长时间内传输了多少字节。有一种有趣的方法in this thread,您或许可以适应。

【讨论】:

    【解决方案2】:

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

    如 Guava 文档中所述: 需要注意的是,请求的许可数量永远不会影响请求本身的限制(调用 acquire(1) 和调用 acquire(1000) 将导致完全相同的限制,如果有的话),但它会影响下一个请求的限制。即,如果一个昂贵的任务到达一个空闲的 RateLimiter,它将立即被授予,但它是下一个请求将经历额外的限制,从而支付昂贵任务的成本。

    【讨论】:

      【解决方案3】:

      这是一个旧帖子,但是这个怎么样:

      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。

      【讨论】:

        猜你喜欢
        • 2021-03-24
        • 2020-12-13
        • 1970-01-01
        • 2014-06-26
        • 1970-01-01
        • 1970-01-01
        • 2016-12-23
        • 2020-07-02
        • 1970-01-01
        相关资源
        最近更新 更多