2010-05-03 131 views
3

我将在Java中实现一个(简单)下载器应用程序作为个人练习。它将在不同的线程中运行多个作业,以便在执行过程中随时在同一时间下载几个文件。如何实现Java下的限制下载速度?

我希望能够定义为所有的下载任务之间共享的下载速率限制,但我不知道怎么甚至单个下载任务去做。我应该如何去做这件事?我应该尝试实施哪些解决方案?

谢谢。

+0

你关心什么,CPU利用率,网络带宽,其他? – 2010-05-03 23:20:28

回答

2

我会从一个管理所有下载的DownloadManager开始。

interface DownloadManager 
{ 
    public InputStream registerDownload(InputStream stream); 
} 

想要参与管理的带宽将其注册与下载管理器流它开始从中读取之前的所有代码。在registerDownload()方法中,管理者将给定的输入流包装在ManagedBandwidthStream中。

public class ManagedBandwidthStream extends InputStream 
    { 
     private DownloadManagerImpl owner; 

     public ManagedBandwidthStream(
      InputStream original, 
      DownloadManagerImpl owner 
     ) 
     { 
     super(original); 
     this.owner = owner; 
     } 

     public int read(byte[] b, int offset, int length) 
     { 
      owner.read(this, b, offset, length); 
     } 

     // used by DownloadManager to actually read from the stream 
     int actuallyRead(byte[] b, int offset, int length) 
     { 
      super.read(b, offset, length); 
     } 

     // also override other read() methods to delegate to the read() above 
    } 

该流确保所有的read()调用被定向回到下载管理器。

class DownloadManagerImpl implements DownloadManager 
{ 
    public InputStream registerDownload(InputStream in) 
    { 
     return new ManagedDownloadStream(in); 
    } 

    void read(ManagedDownloadStream source, byte[] b, int offset, int len) 
    { 
     // all your streams now call this method. 
     // You can decide how much data to actually read. 
     int allowed = getAllowedDataRead(source, len); 
     int read = source.actuallyRead(b, offset, len); 
     recordBytesRead(read); // update counters for number of bytes read 
    } 
} 

您的带宽分配策略是关于如何实现getAllowedDataRead()。

一个简单的限制带宽的方法是, 保存一个计数器,指出在给定的时间段(例如1秒)内可以读取多少个字节。每次读取调用检查计数器并使用它来限制读取的实际字节数。计时器用于重置计数器。

实际上,多个流中带宽的分配可能相当复杂,特别是避免饥饿和促进公平,但这应该给你一个公平的开始。

+0

太好了,谢谢你的代码,这应该是很多让我开始! – JohnWithoutArms 2010-05-03 23:52:15

+0

太好了。一个你不再使用的'allowed'变量如何影响带宽使用?这里没有任何东西可以控制带宽。这里的答案实际上是什么? – EJP 2016-09-05 09:20:45

+0

如果你闭上眼睛,那么你就不会看到它。正如我在答案中所说的,我正在展示一种管理许多数据流带宽的模式。当然,继续往下看,完全有效的理由,只是因为你无法阅读所写的内容。 – mdma 2016-09-06 02:34:01

1
  1. 发送/接收数据
  2. 睡眠
  3. 重复

那基本上是如何最限制器工作(就像wget

2

这个问题是waaaaay高的水平,所以我希望你不要指望低级别的答案。一般来说,您首先需要定义/决定您将使用的网络实用程序。例如,你打算打开一个标准的Java Socket吗?你会使用一些第三方网络库吗?你是否熟悉过任何可用的选项?

在最一般的意义上,你可以通过你决定在网络库控制带宽。它应该是一个相对简单的公式。

你将有一些类型的对象(称之为插座)您设置的带宽限制。您将设置套​​接字的带宽限制(一般情况下)为总带宽/活动连接数。如果某些连接未使用其全部带宽分配,则可以持续优化此数字。要求对算法的帮助,当你到达那里,如果你更在乎...

等式的第二部分将是,可以在OS /网络库已经只是给它一个速率控制你的带宽限制数量,还是你需要通过限制读/写速率来控制这个过程?这并不像看起来那么直截了当,因为一个操作系统可以有TCP套接字缓冲区,直到数据完整时才会读入数据。假设你有一个2Mb的入站流量套接字缓冲区。如果您依赖远程端只在2Mb缓冲区满时停止发送数据,则必须等待2Mb的数据传输,然后才有机会通过从队列中移除进行速率限制,您将始终有一个巨大的突发在每个套接字之前您都可以限制速度。

此时你开始谈论编写一个将通过tcp(或UDP)运行的协议,以便一方可以告诉另一方,“确定发送更多数据”或“等待,我的带宽限制已暂时停止击中”。长话短说,开始,然后问问题,一旦你有一个实施的地方,并希望改善它...

4
  1. 决定你想要使用多少带宽,以字节/秒。
  2. 建立到目标的网络路径延迟,以秒为单位。
  3. 乘法得到以字节为单位的答案(字节/秒*秒=字节)。
  4. 除以并发连接数。
  5. 将每个连接的套接字接收缓冲区设置为该数字。
+0

有什么办法,Java SocketChannel提供了限制每秒传输字节速度,而不是限制传输速度的写逻辑? – rns 2014-08-11 06:22:35

+2

@Soni这正是我的回答已经描述的。你甚至读过它吗? – EJP 2014-08-11 06:31:07