当前位置:七道奇文章资讯编程技术Java编程
日期:2011-03-22 16:14:00  来源:本站整理

HTTP多线程断点续传下载的尝试[Java编程]

赞助商链接



  本文“HTTP多线程断点续传下载的尝试[Java编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:

直接看代码吧,废话一点不多说.

功效介绍:

1 多线程HTTP下载

2 支持断点续传

3 暂时文件下载,成功后改名

4 供应防盗链的破解

Java代码

package net.java2000.tools;

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;

/**
 * HTTP的多线程下载工具.
 *
 * @author 赵学庆 www.java2000.net
 */
public class HTTPDownloader extends Thread {
  // 要下载的页面
  private String page;

  // 保存的途径
  private String savePath;

  // 线程数
  private int threadNumber = 2;

  // 根源地址
  private String referer;

  private String cookie;

  int threadPointer = 0;

  private Map<Integer, HTTPDownloaderThread> threadPool =  new HashMap<Integer, HTTPDownloaderThread>(); // 线程迟    

  // 最小的块尺寸.假如文件尺寸除以线程数小于这个,则会削减线程数.
  private int MIN_BLOCK = 10 * 1024;

  public static void main(String[] args) throws Exception  {
    HTTPDownloader d = new HTTPDownloader ("http://www.xxxxx.com/a.rar", null,  "d://a.rar", 10, null);
    d.down();
  }

  public void run() {
    try {
      down();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * 下载操作
   *
   * @throws Exception
   */
  public void down() throws Exception {
    URL url = new URL(page); // 成立URL
    URLConnection con = url.openConnection(); // 成立衔接
    con.setRequestProperty("Referer", referer == null  ? page : referer);
    con.setRequestProperty("UserAgent",  "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;  flashget)");
    int contentLen = con.getContentLength(); // 得到资源长度
    if ((contentLen / MIN_BLOCK + 1) < threadNumber)  {
      threadNumber = contentLen / MIN_BLOCK + 1; // 调整 下载线程数
    }
    if (threadNumber > 10) {
      threadNumber = 10;
    }
    int begin = 0;
    int step = contentLen / threadNumber + 1;
    int end = 0;
    HTTPDownloaderThread thread;
    for (threadPointer = 0; threadPointer < threadNumber;  threadPointer++) {
      end += step;
      if (end > contentLen) {
        end = contentLen;
      }
      thread = new HTTPDownloaderThread(this, threadPointer,  begin, end);
      threadPool.put(threadPointer, thread);
      thread.start();
      begin = end;
    }
  }

  /**
   * 一个线程完活了.
   *
   * @param id 完活的线程id
   */
  public synchronized void finished(int id) {
    threadNumber--;
    threadPool.remove(id);
    if (threadNumber <= 0) {
      System.out.println("FINISHED:" + savePath);
      File f1 = new File(savePath + ".tmp");
      File f2 = new File(savePath);
      // 假如目标文件已经存在,则尝试删除它
      // 最多尝试3次,隔断1秒钟.
      int times = 3;
      while (f2.exists() && times > 0) {
        if (f2.delete()) {
          break;
        }
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        times--;
      }
      if (!f2.exists()) {
        if (!f1.renameTo(f2)) {
          System.out.println("改名失利!");
        }
      } else {
        System.out.println("目标文件存在,且无法删除,无法 改名");
      }
    } else {
      int size = 0;
      HTTPDownloaderThread o = null;
      // 尝试查找一个可以分担的线程
      for (HTTPDownloaderThread thread : threadPool.values ()) {
        if (thread.endPos - thread.curPos > size)  {
          size = thread.endPos - thread.curPos;
          o = thread;
        }
      }
      if (size > MIN_BLOCK * 2) {
        if (o.isAlive()) {
          int endPos = o.endPos;
          int beginPos = o.endPos - ((o.endPos -  o.curPos) / 2);
          o.endPos = beginPos;
          threadNumber++;
          threadPointer++;
          HTTPDownloaderThread thread = new  HTTPDownloaderThread(this, threadPointer, beginPos, endPos);
          threadPool.put(threadPointer, thread);
          System.out.println("A Help Thread for  " + o.id + " is started with:" +  threadPointer);
          thread.start();
        }
      }
    }
  }

  public HTTPDownloader() {
  }

  /**
   * 下载
   *
   * @param page 被下载的页面
   * @param savePath 保存的途径
   */
  public HTTPDownloader(String page, String savePath) {
    this(page, savePath, 10);
  }

  /**
   * 下载
   *
   * @param page 被下载的页面
   * @param savePath 保存的途径
   * @param threadNumber 线程数
   */
  public HTTPDownloader(String page, String savePath, int  threadNumber) {
    this(page, page, savePath, 10, null);
  }

  /**
   * 下载
   *
   * @param page 被下载的页面
   * @param savePath 保存的途径
   * @param threadNumber 线程数
   * @param referer 根源
   */
  public HTTPDownloader(String page, String referer, String  savePath, int threadNumber, String cookie) {
    this.page = page;
    this.savePath = savePath;
    this.threadNumber = threadNumber;
    this.referer = referer;
  }

  public String getPage() {
    return page;
  }

  public void setPage(String page) {
    this.page = page;
  }

  public String getSavePath() {
    return savePath;
  }

  public void setSavePath(String savePath) {
    this.savePath = savePath;
  }

  public int getThreadNumber() {
    return threadNumber;
  }

  public void setThreadNumber(int threadNumber) {
    this.threadNumber = threadNumber;
  }

  public String getReferer() {
    return referer;
  }

  public void setReferer(String referer) {
    this.referer = referer;
  }

  public String getCookie() {
    return cookie;
  }

  public void setCookie(String cookie) {
    this.cookie = cookie;
  }
}

/**
 * 下载线程
 *
 * @author 赵学庆 www.java2000.net
 */
class HTTPDownloaderThread extends Thread {
  HTTPDownloader manager;

  int startPos;

  int endPos;

  int id;

  int curPos;

  int BUFFER_SIZE = 40960;

  int readByte = 0;

  HTTPDownloaderThread(HTTPDownloader manager, int id, int  startPos, int endPos) {
    this.id = id;
    this.manager = manager;
    this.startPos = startPos;
    this.endPos = endPos;
  }

  public void run() {
    System.out.println("线程" + id + "启 动," + startPos + "-" + endPos);
    // 成立一个buff
    BufferedInputStream bis = null;
    RandomAccessFile fos = null;
    // 缓冲区大小
    byte[] buf = new byte[BUFFER_SIZE];
    boolean timeout = false;
    Socket socket = null;
    try {
      curPos = startPos;
      File file = new File(manager.getSavePath() +  ".tmp");
      // 成立RandomAccessFile
      fos = new RandomAccessFile(file, "rw");
      // 从startPos开始
      fos.seek(startPos);
      int index = manager.getPage().indexOf("/",  8);
      String host = manager.getPage().substring(7,  index);
      // System.out.println(host);
      socket = new Socket(host, 80);
      socket.setSoTimeout(30000);
      // 写入数据
      BufferedWriter wr = new BufferedWriter(new  OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
      StringBuilder b = new StringBuilder();
      b.append("GET " + manager.getPage ().substring(index) + " HTTP/1.1rn");
      b.append("Host: " + host +  "rn");
      b.append("Referer: " + (manager.getReferer()  == null ? manager.getPage() : manager.getReferer()) +  "rn");
      b.append("UserAgent: Mozilla/4.0 (compatible; MSIE  6.0; Windows NT 5.1; flashget; rn");
      b.append("Range: bytes=" + startPos +  "-" + endPos + "rn");
      b.append("rn");
      // System.out.println(b.toString());
      wr.write(b.toString());
      wr.flush();
      // 下面一段向按照文件写入数据,curPos为当前写入的未知,这里 会判断能否小于endPos,
      // 假如超越endPos就代表该线程已经履行完毕
      bis = new BufferedInputStream(socket.getInputStream ());
      // 读取直到换行
      int ch;
      boolean foundBR = false;
      while (true) {
        ch = bis.read();
        if (ch == 0xD) {
          ch = bis.read();
          if (ch == 0xA) {
            if (foundBR) {
              break;
            }
            foundBR = true;
          } else {
            foundBR = false;
          }
        } else {
          foundBR = false;
        }
      }
      int len = -1;
      while (curPos < endPos) {
        // System.out.println(id + "=" +  (endPos - curPos));
        len = bis.read(buf, 0, BUFFER_SIZE);
        if (len == -1) {
          break;
        }
        fos.write(buf, 0, len);
        // System.out.println(id + "=Write OK! ");
        curPos = curPos + len;
        if (curPos > endPos) {
          // 获得精确读取的字节数
          readByte += len - (curPos - endPos) +  1;
        } else {
          readByte += len;
        }
      }
      System.out.println("线程" + id + "已经 下载完毕:" + readByte);
    } catch (Exception ex) {
      timeout = true;
    } finally {
      if (bis != null) {
        try {
          bis.close();
        } catch (Exception e) {
          System.out.println("关闭文件失利(1)! ");
        }
      }
      if (fos != null) {
        try {
          fos.close();
        } catch (Exception e) {
          System.out.println("关闭文件失利(2)! ");
        }
      }
      if (socket != null) {
        try {
          socket.close();
        } catch (Exception e) {
          System.out.println("关闭链接失利!");
        }
      }
    }
    if (timeout) {
      System.out.println(id + " timeout,  restart...");
      new HTTPDownloaderThread(manager, id, curPos,  endPos).start();
    } else {
      manager.finished(id);
    }
  }
}


  以上是“HTTP多线程断点续传下载的尝试[Java编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
  • win8 Could not load type System.ServiceModel.Activation.HttpModule 错误办理筹划
  • MSXML2.ServerXMLHTTP 对象具体属性、办法阐明
  • linux下https的搭建总结
  • CentOS下lighttpd+php安装
  • Windows下Apache、Lighttpd、 Nginx(Ngwsx)静态文件拜候测试比较
  • CentOS 6.2 X86 上布置IBM HTTPserver7.0
  • 详解 Nginx + Tomcat HTTPS/SSL 配置办法
  • Nginx https 免费SSL证书配置指南
  • Asp WinHttp.WinHttpRequest.5.1 对象利用详解
  • PHP利用udp模拟http恳求
  • Cache篇:操纵HTTP指令举行攻击
  • Apache服务以及httpd.conf配置详解
  • 本文地址: 与您的QQ/BBS好友分享!
    • 好的评价 如果您觉得此文章好,就请您
        0%(0)
    • 差的评价 如果您觉得此文章差,就请您
        0%(0)

    文章评论评论内容只代表网友观点,与本站立场无关!

       评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
    Copyright © 2020-2022 www.xiamiku.com. All Rights Reserved .