2010-05-03 1 views
3

개인용 연습으로 Java에서 (간단한) 다운로더 응용 프로그램을 구현할 것입니다. 실행 중에 동시에 여러 파일을 다운로드하는 방식으로 여러 스레드에서 여러 작업을 실행하려고합니다.Java에서 다운로드 속도가 어떻게 제한 될 수 있습니까?

모든 다운로드 작업간에 공유되는 다운로드 속도 제한을 정의 할 수 있기를 원하지만 단일 다운로드 작업으로도 수행하는 방법을 모르겠습니다. 어떻게해야합니까? 구현하려는 솔루션은 무엇입니까?

감사합니다.

+0

CPU 사용률, 네트워크 대역폭, 기타는 무엇입니까? –

답변

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 초)에 몇 바이트를 더 읽을 수 있는지 카운터를 유지하는 것입니다. read를 호출 할 때마다 카운터를 검사하여이를 사용하여 읽은 실제 바이트 수를 제한합니다. 타이머를 사용하여 카운터를 재설정합니다.

실제로 여러 스트림 사이에서 대역폭 할당은 기아를 피하고 공정성을 높이기 위해 매우 복잡 할 수 있지만 이는 공정한 시작을 제공합니다.

+0

위대한, 코드 주셔서 감사합니다,이 날 시작 충분해야합니다! – JohnWithoutArms

+0

좋습니다. 더 이상 사용하지 않는'allowed' 변수가 대역폭 사용에 어떻게 영향을 줄 수 있습니까? 대역폭을 제어 할 수있는 것은 여기에 없습니다. 실제로 대답은 무엇입니까? – EJP

+0

눈을 감춰두면 눈에 띄지 않게됩니다. 내가 응답에서 말했듯이, 나는 많은 스트림들 사이에서 대역폭을 관리하기위한 패턴을 보여주고 있습니다. 물론, 앞으로 가서 downvote, 완벽하게 유효한 이유는 단지 당신이 쓰여진 것을 읽는 것을 귀찮게 할 수 없기 때문입니다. – mdma

1
  1. 보내기/데이터를 수신
  2. 수면
  3. 반복

그게 기본적으로 대부분이 질문은 절대로 안돼요 높은 수준, 그래서 내가 당신을 희망

2

(단지 wget 같은) 작업 리미터 방법 낮은 수준의 대답을 기대하지 마십시오. 일반적으로 어떤 네트워크 유틸리티를 사용할지 정의/결정해야합니다. 예를 들어 표준 Java 소켓을 열려고합니까? 어떤 써드 파티 네트워크 라이브러리를 사용할 것입니까? 사용 가능한 옵션 중 하나라도 익혔습니까?

가장 일반적인 의미에서 결정한 네트워킹 라이브러리를 통해 대역폭을 제어 할 수 있습니다. 비교적 간단한 수식이어야합니다.

대역폭 제한을 설정하는 일종의 객체 (소켓이라고 함)가 있습니다. 소켓의 대역폭 제한 (일반적으로)을 전체 대역폭/활성 연결 수로 설정합니다. 일부 연결에서 전체 대역폭 할당을 사용하지 않는 경우이 번호를 지속적으로 최적화 할 수 있습니다. 해당 알고리즘에 대한 도움을 요청하십시오.

방정식의 두 번째 부분은 OS/네트워크 라이브러리가 이미 속도를 제공하여 대역폭을 제어 할 수 있습니까? 또는 읽기/쓰기 속도를 제한하여이 프로세스를 직접 제어해야합니까? 이것은 OS가 TCP 소켓 버퍼를 가질 수 있기 때문에 보이는 것처럼 간단하지 않습니다. TCP 소켓 버퍼는 데이터가 가득 찰 때까지 읽습니다. 인바운드 트래픽을위한 2MB 소켓 버퍼가 있다고 가정합니다. 원격 측에서 2Mb 버퍼가 꽉 찼을 때 데이터 전송을 멈추는 것에 의존한다면 대기열에서 제거하여 속도 제한을 적용하기 전에 2Mb의 데이터가 전송 될 때까지 기다려야합니다. 속도 제한 전에 모든 소켓에.

그 시점에서 TCP (또는 UDP)를 통해 실행되는 프로토콜 작성에 대해 이야기하기 시작합니다. 즉, 한 쪽에서 다른 쪽에서 "Ok send more data"또는 "wait, my bandwidth limit is temporary 히트". 간단히 말하자면 구현을 시작한 후에 질문을하십시오.

4
  1. 사용할 대역폭을 바이트/초 단위로 결정하십시오.
  2. 대상에 대한 네트워크 경로의 지연을 초 단위로 설정하십시오.
  3. 바이트로 응답을 얻으려면 곱하십시오 (바이트/초 * 초 = 바이트).
  4. 동시 연결 수로 나눕니다.
  5. 각 연결의 소켓 수신 버퍼를이 번호로 설정하십시오.
+0

java SocketChannel은 전송 속도를 제한하는 쓰기 논리 대신 초당 전송 바이트 속도를 제한하는 방법이 있습니까? – rns

+2

@Soni 정확히 내 대답은 이미 설명하는 것입니다. 읽어 봤니? – EJP