2010-05-03 128 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