三、多線程斷點續傳

三、多線程斷點續傳

  • 多線程下載

    原理:服務器CPU分配給每條線程的時間片相同,服務器帶寬平均分配給每條線程,所以客戶端開啓的線程越多,就能搶佔到更多的服務器資源

    確定每條線程下載多少數據
    發送http請求至下載地址

    String path = "http://192.168.2.102:8080/3.mp3";        
    URL url = new URL(path);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setReadTimeout(5000);
    conn.setConnectTimeout(5000);
    conn.setRequestMethod("GET");                   
    

    獲取文件總長度,然後創建長度一致的臨時文件

    if(conn.getResponseCode() == 200){
        //獲得服務器流中數據的長度
        int length = conn.getContentLength();
        //創建一個臨時文件存儲下載的數據
        RandomAccessFile raf = new RandomAccessFile(getFileName(path), "rwd");
        //設置臨時文件的大小
        raf.setLength(length);
        raf.close();
    

    確定線程下載多少數據

        //計算每個線程下載多少數據
        int blockSize = length / THREAD_COUNT;
    

    計算每條線程下載數據的開始位置和結束位置

    for(int id = 1; id <= 3; id++){
        //計算每個線程下載數據的開始位置和結束位置
        int startIndex = (id - 1) * blockSize;
        int endIndex = id * blockSize - 1;
        if(id == THREAD_COUNT){
            endIndex = length;
        }
    
        //開啓線程,按照計算出來的開始結束位置開始下載數據
        new DownLoadThread(startIndex, endIndex, id).start();
    }
    

    在開啓的子線程中進行下載
    再次發送請求至下載地址,請求開始位置至結束位置的數據

    String path = "http://192.168.1.102:8080/editplus.exe";
    
    URL url = new URL(path);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setReadTimeout(5000);
    conn.setConnectTimeout(5000);
    conn.setRequestMethod("GET");
    
    //向服務器請求部分數據
    conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
    conn.connect();
    

    下載請求到的數據,存放至臨時文件中

    if(conn.getResponseCode() == 206){
        InputStream is = conn.getInputStream();
        RandomAccessFile raf = new RandomAccessFile(getFileName(path), "rwd");
        //指定從哪個位置開始存放數據
        raf.seek(startIndex);
        byte[] b = new byte[1024];
        int len;
        while((len = is.read(b)) != -1){
            raf.write(b, 0, len);
        }
        raf.close();
    }
    
  • 多線程斷點續傳

    多線程下載步驟:

    • 1.發送Http請求至下載地址
    • 2.成功響應後獲取服務器流中的數據長度
    • 3.創建一個臨時文件(RandomAccessFile)存儲下載的數據,給臨時文件設置大小
    • 4.開啓循環,計算每個線程下載的數據長度,即下載數據的開始位置和結束位置
    • 5.同時開啓線程,按照計算的位置開始下載
    • 6.在線程中向服務器請求部分數據
    • 7.將請求到的數據存放在臨時文件中,並指定從哪個位置存放數據

    帶斷點續傳的多線程下載
    定義一個int變量記錄每條線程下載數據的總長度,然後加上該線程下載的開始位置,
    得到的結果就是下次下載時,該線程開始的位置,把下載位置記錄在緩存文件中

    步驟:

    • 1每次下載都把新的下載位置寫入緩存文本文件中
    • 2下次下載開始時,先讀取緩存文件中的值,得到的值就是該線程新的開始位置
    • 3三條線程都下載完畢之後,刪除緩存文件(注意刪除過程要同步)

      //開啓子線程進行屬於耗時操作的網絡下載
      Thread t=new Thread(){
      
      @Override
      public void run() {
          try {
              URL url=new URL(path);
              HttpURLConnection conn=(HttpURLConnection) url.openConnection();
              conn.setRequestMethod("GET");
              conn.setConnectTimeout(5000);
              conn.setReadTimeout(5000);
              if(conn.getResponseCode()==200){
                  //得到數據資源的大小
                  int length=conn.getContentLength();
      
                  File file=new File(Environment.getExternalStorageDirectory(),"asd.rmvb");
      
                  //創建臨時文件,參數file,“rwd”決定了臨時文件的位置和權限
                  RandomAccessFile raf=new RandomAccessFile(file, "rwd");
                  //設置臨時文件的大小
                  raf.setLength(length);
                  raf.close();
      
                  int size=length/threadcount;
                  for(int i=0;i<threadcount;i++){
                      //計算每條線程下載開始的位置
                      int startindex=i*size;
                      int endindex=(i+1)*size-1;
                      if(i==threadcount-1){
                          endindex=length-1;
                      }
      
                      //開啓子線程下載
                      new MyThread(startindex, endindex, i).start();
                  }
              }
          } catch (Exception e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
      }
      

      };

    下面是子線程類

    class MyThread extends Thread{
        private int startindex;
        private int endindex;
        private int threadId;
        public MyThread(int startindex, int endindex, int threadId) {
            super();
            this.startindex = startindex;
            this.endindex = endindex;
            this.threadId = threadId;
        }
        public void run(){
    
            try {
                //創建記錄子線程的下載進程的文件
                File progressfile=new File(Environment.getExternalStorageDirectory(),threadId+".txt");
                if(progressfile.exists()){
                    FileInputStream is=new FileInputStream(progressfile);
                    BufferedReader bufr=new BufferedReader(new InputStreamReader(is));
                    int progress=Integer.parseInt(bufr.readLine());
                    startindex+=progress;
                    currentprogress+=progress;
                    pb.setProgress(progress);
    
                    Message msg=handler.obtainMessage();
                    handler.sendEmptyMessage(1);
    
                    bufr.close();
                }
    
                URL url=new URL(path);
                HttpURLConnection conn=(HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(5000);
                //分段請求網絡數據
                conn.setRequestProperty("Range", "bytes="+startindex+"-"+endindex);
    
                if(conn.getResponseCode()==200){
                    InputStream is=conn.getInputStream();
                    byte[] b=new byte[1024];
                    int len=0;
    
                    int total=0;
                    File file=new File(Environment.getExternalStorageDirectory(),"asd.rmvb");
                    RandomAccessFile raf=new RandomAccessFile(file, "rwd");
    
                    raf.seek(startindex);
                    while((len=is.read(b))!=-1){
                        raf.write(b,0,len);
                        total+=len;
                        currentprogress+=len;
                        pb.setProgress(currentprogress);
                        Message msg=handler.obtainMessage();
                        handler.sendEmptyMessage(1);
    
    
                    //File progressfile=new File(threadId+".txt");
                    RandomAccessFile progressraf=new RandomAccessFile(progressfile, "rwd");
                    progressraf.write((total+"").getBytes());
                    progressraf.close();
                }
    
                finishedthread++;
                synchronized (path) {
                    if(finishedthread==threadcount){
                        for(int i=0;i<threadcount;i++){
                            File f=new File(threadId+".txt");
                            f.delete();
                            finishedthread=0;
                        }
                    }
                }
            }
    
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    
    }
    

    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章