客户端;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class ArcSyncHttpClient {
public static void main(String[] args) throws Exception {

String strURL = "http://localhost:8080/ArcSyncHttpDownload/httpServlet";
URL downUrl = new URL(strURL);
HttpURLConnection cn = (HttpURLConnection) downUrl.openConnection();
if (cn.getResponseCode() == 200) {
// InputStream is = cn.getInputStream();
int part_count = 10;

int contentLength = cn.getContentLength();
System.out.println("cn.getContentLength():"+cn.getContentLength());
int firstLength = contentLength / part_count;
System.out.println("firstLength():" + firstLength);
cn.disconnect();
// part_count = 1;
for (int i = 1; i < part_count+1; i++) {
if (i==part_count) {
// int lastLength = contentLength -firstLength*(part_count-1);
File saveFile = new File("E:/test/123",String.format("123_0%d.mp3", i));
TestDownload.download(saveFile.getName(), saveFile.getParent(),
strURL, (i-1)*firstLength, contentLength);
}else {
File saveFile = new File("E:/test/123",String.format("123_0%d.mp3", i));
TestDownload.download(saveFile.getName(), saveFile.getParent(),
strURL, (i-1)*firstLength, firstLength*i);
}

}
}
}

public static void download( String fileName, String filePath,String remoteUrl, long start ,long end) {
byte[] buf = new byte[10240];
HttpURLConnection httpURLConnection;
URL url;
BufferedInputStream bis;
int size;
RandomAccessFile rndFile;
// 下载文件
try {
url = new URL(remoteUrl);
httpURLConnection = (HttpURLConnection)url.openConnection();
// 设置User-Agent
httpURLConnection.setRequestProperty("User-Agent", "Net");
// 设置续传开始
httpURLConnection.setRequestProperty("Range", "bytes=" + start + "-"+ end);
// 获取输入流
bis = new BufferedInputStream(httpURLConnection.getInputStream());
rndFile = new RandomAccessFile(filePath + "\\" + fileName, "rw");
rndFile.seek(0);
int i = 0;
while ((size = bis.read(buf)) != -1) {
//if (i > 500) break;
rndFile.write(buf, 0, size);

i++;
}
System.out.println("i=" + i);
httpURLConnection.disconnect();
bis.close();
rndFile.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}

public static long getRemoteFileSzie(String url) {
long size = 0;
try {
HttpURLConnection httpUrl = (HttpURLConnection)(new URL(url)).openConnection();
size = httpUrl.getContentLength();
httpUrl.disconnect();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return size;
}

public static void mergeFiles(String outFile, List<String> files) {
FileChannel outChannel = null;
System.out.println("Merge " + files + " into " + outFile);
try {
outChannel = new FileOutputStream(outFile).getChannel();
for (String f : files) {
FileChannel fc = new FileInputStream(f).getChannel();
ByteBuffer bb = ByteBuffer.allocate(BUFSIZE);
while (fc.read(bb) != -1) {
bb.flip();
outChannel.write(bb);
bb.clear();
}
fc.close();
}
System.out.println("Merged!! ");
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {
if (outChannel != null) {
outChannel.close();
}
} catch (IOException ignore) {
}
}
}

}

服务端

package com.defonds.cds.common;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//HTTP 断点续传 demo(客户端测试工具:快车、迅雷)
public class ArcSyncHttpDownloadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// final static Log log = LogFactory.getLog(ArcSyncHttpDownloadServlet.class);

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
File downloadFile = new File("E:/test/123.mp3");//要下载的文件
long fileLength = downloadFile.length();//记录文件大小
System.out.println("fileLength:"+fileLength);
long pastLength = 0;//记录已下载文件大小
int rangeSwitch = 0;//0:从头开始的全文下载;1:从某字节开始的下载(bytes=27000-);2:从某字节开始到某字节结束的下载(bytes=27000-39000)
long toLength = 0;//记录客户端需要下载的字节段的最后一个字节偏移量(比如bytes=27000-39000,则这个值是为39000)
long contentLength = 0;//客户端请求的字节总量
String rangeBytes = "";//记录客户端传来的形如“bytes=27000-”或者“bytes=27000-39000”的内容
RandomAccessFile raf = null;//负责读取数据
OutputStream os = null;//写出数据
OutputStream out = null;//缓冲
byte b[] = new byte[1024];//暂存容器

if (request.getHeader("Range") != null) {// 客户端请求的下载的文件块的开始字节
response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);
System.out.println("request.getHeader(\"Range\")=" + request.getHeader("Range"));
rangeBytes = request.getHeader("Range").replaceAll("bytes=", "");
int index = rangeBytes.indexOf('-');
int length = rangeBytes.length()-1;
if (index == 1) {//bytes=969998336-
rangeSwitch = 1;
// rangeBytes = rangeBytes.substring(0, rangeBytes.indexOf('-'));
String temp0 = rangeBytes.substring(0,rangeBytes.indexOf('-'));
String temp2 = rangeBytes.substring(rangeBytes.indexOf('-') + 1, rangeBytes.length());
pastLength = Long.parseLong(temp0.trim());
if ("".equals(temp2)) {
contentLength = fileLength - pastLength + 1;//客户端请求的是 969998336 之后的字节
}else {
toLength = Long.parseLong(temp2);//bytes=1275856879-1275877358,到第 1275877358 个字节结束
contentLength = toLength - pastLength + 1;//客户端请求的是 1275856879-1275877358 之间的字节
}
} else {//bytes=1275856879-1275877358
rangeSwitch = 2;
String temp0 = rangeBytes.substring(0,rangeBytes.indexOf('-'));
String temp2 = rangeBytes.substring(rangeBytes.indexOf('-') + 1, rangeBytes.length());
pastLength = Long.parseLong(temp0.trim());//bytes=1275856879-1275877358,从第 1275856879 个字节开始下载
toLength = Long.parseLong(temp2);//bytes=1275856879-1275877358,到第 1275877358 个字节结束
contentLength = toLength - pastLength + 1;//客户端请求的是 1275856879-1275877358 之间的字节
}
} else {//从开始进行下载
contentLength = fileLength;//客户端要求全文下载
}

/**
* 如果设设置了Content-Length,则客户端会自动进行多线程下载。如果不希望支持多线程,则不要设置这个参数。
* 响应的格式是:
* Content-Length: [文件的总大小] - [客户端请求的下载的文件块的开始字节]
* ServletActionContext.getResponse().setHeader("Content-Length",
* new Long(file.length() - p).toString());
*/
response.reset();//告诉客户端允许断点续传多线程连接下载,响应的格式是:Accept-Ranges: bytes
response.setHeader("Accept-Ranges", "bytes");//如果是第一次下,还没有断点续传,状态是默认的 200,无需显式设置;响应的格式是:HTTP/1.1 200 OK
if (pastLength != 0) {
//不是从最开始下载,
//响应的格式是:
//Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]/[文件的总大小]
System.out.println("----------------------------不是从开始进行下载!服务器即将开始断点续传...");
switch (rangeSwitch) {
case 1 : {//针对 bytes=27000- 的请求
String contentRange = new StringBuffer("bytes ").append(new Long(pastLength).toString()).append("-").append(new Long(fileLength - 1).toString()).append("/").append(new Long(fileLength).toString()).toString();
response.setHeader("Content-Range", contentRange);
break;
}
case 2 : {//针对 bytes=27000-39000 的请求
String contentRange = rangeBytes + "/" + new Long(fileLength).toString();
response.setHeader("Content-Range", contentRange);
break;
}
default : {
break;
}
}
} else {
//是从开始下载
System.out.println("----------------------------是从开始进行下载!");
}

try {
response.addHeader("Content-Disposition", "attachment; filename=\"" + downloadFile.getName() + "\"");
response.setContentType( CommonUtil.setContentType(downloadFile.getName()));// set the MIME type.
response.addHeader("Content-Length", String.valueOf(contentLength));
os = response.getOutputStream();
out = new BufferedOutputStream(os);
raf = new RandomAccessFile(downloadFile, "r");
try {
switch (rangeSwitch) {
case 0 : {//普通下载,或者从头开始的下载
//同1
}
case 1 : {//针对 bytes=27000- 的请求
raf.seek(pastLength);//形如 bytes=969998336- 的客户端请求,跳过 969998336 个字节
int n = 0;
while ((n = raf.read(b, 0, 1024)) != -1) {
out.write(b, 0, n);
}
break;
}
case 2 : {//针对 bytes=27000-39000 的请求
raf.seek(pastLength - 1);//形如 bytes=1275856879-1275877358 的客户端请求,找到第 1275856879 个字节
int n = 0;
long readLength = 0;//记录已读字节数
while (readLength <= contentLength - 1024) {//大部分字节在这里读取
n = raf.read(b, 0, 1024);
readLength += 1024;
out.write(b, 0, n);
}
if (readLength <= contentLength) {//余下的不足 1024 个字节在这里读取
n = raf.read(b, 0, (int)(contentLength - readLength));
out.write(b, 0, n);
}
//
// raf.seek(pastLength);//形如 bytes=1275856879-1275877358 的客户端请求,找到第 1275856879 个字节
// while (raf.getFilePointer() < toLength) {
// out.write(raf.read());
// }
break;
}
default : {
break;
}
}
out.flush();
} catch(IOException ie) {
/**
* 在写数据的时候,
* 对于 ClientAbortException 之类的异常,
* 是因为客户端取消了下载,而服务器端继续向浏览器写入数据时,
* 抛出这个异常,这个是正常的。
* 尤其是对于迅雷这种吸血的客户端软件,
* 明明已经有一个线程在读取 bytes=1275856879-1275877358,
* 如果短时间内没有读取完毕,迅雷会再启第二个、第三个。。。线程来读取相同的字节段,
* 直到有一个线程读取完毕,迅雷会 KILL 掉其他正在下载同一字节段的线程,
* 强行中止字节读出,造成服务器抛 ClientAbortException。
* 所以,我们忽略这种异常
*/
//ignore
}
} catch (Exception e) {
System.err.println( e);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
System.err.println( e);
}
}
if (raf != null) {
try {
raf.close();
} catch (IOException e) {
System.err.println( e);
}
}
}
}
}

package com.defonds.cds.common;
public class CommonUtil {

public static String setContentType(String returnFileName) {
String contentType = "application/octet-stream";
if (returnFileName.lastIndexOf(".") < 0)
return contentType;
returnFileName = returnFileName.toLowerCase();
returnFileName = returnFileName.substring(returnFileName
.lastIndexOf(".") + 1);

if (returnFileName.equals("html") || returnFileName.equals("htm")
|| returnFileName.equals("shtml")) {
contentType = "text/html";
} else if (returnFileName.equals("css")) {
contentType = "text/css";
} else if (returnFileName.equals("xml")) {
contentType = "text/xml";
} else if (returnFileName.equals("gif")) {
contentType = "image/gif";
} else if (returnFileName.equals("jpeg")
|| returnFileName.equals("jpg")) {
contentType = "image/jpeg";
} else if (returnFileName.equals("js")) {
contentType = "application/x-javascript";
} else if (returnFileName.equals("atom")) {
contentType = "application/atom+xml";
} else if (returnFileName.equals("rss")) {
contentType = "application/rss+xml";
} else if (returnFileName.equals("mml")) {
contentType = "text/mathml";
} else if (returnFileName.equals("txt")) {
contentType = "text/plain";
} else if (returnFileName.equals("jad")) {
contentType = "text/vnd.sun.j2me.app-descriptor";
} else if (returnFileName.equals("wml")) {
contentType = "text/vnd.wap.wml";
} else if (returnFileName.equals("htc")) {
contentType = "text/x-component";
} else if (returnFileName.equals("png")) {
contentType = "image/png";
} else if (returnFileName.equals("tif")
|| returnFileName.equals("tiff")) {
contentType = "image/tiff";
} else if (returnFileName.equals("wbmp")) {
contentType = "image/vnd.wap.wbmp";
} else if (returnFileName.equals("ico")) {
contentType = "image/x-icon";
} else if (returnFileName.equals("jng")) {
contentType = "image/x-jng";
} else if (returnFileName.equals("bmp")) {
contentType = "image/x-ms-bmp";
} else if (returnFileName.equals("svg")) {
contentType = "image/svg+xml";
} else if (returnFileName.equals("jar") || returnFileName.equals("var")
|| returnFileName.equals("ear")) {
contentType = "application/java-archive";
} else if (returnFileName.equals("doc")) {
contentType = "application/msword";
} else if (returnFileName.equals("pdf")) {
contentType = "application/pdf";
} else if (returnFileName.equals("rtf")) {
contentType = "application/rtf";
} else if (returnFileName.equals("xls")) {
contentType = "application/vnd.ms-excel";
} else if (returnFileName.equals("ppt")) {
contentType = "application/vnd.ms-powerpoint";
} else if (returnFileName.equals("7z")) {
contentType = "application/x-7z-compressed";
} else if (returnFileName.equals("rar")) {
contentType = "application/x-rar-compressed";
} else if (returnFileName.equals("swf")) {
contentType = "application/x-shockwave-flash";
} else if (returnFileName.equals("rpm")) {
contentType = "application/x-redhat-package-manager";
} else if (returnFileName.equals("der") || returnFileName.equals("pem")
|| returnFileName.equals("crt")) {
contentType = "application/x-x509-ca-cert";
} else if (returnFileName.equals("xhtml")) {
contentType = "application/xhtml+xml";
} else if (returnFileName.equals("zip")) {
contentType = "application/zip";
} else if (returnFileName.equals("mid")
|| returnFileName.equals("midi")
|| returnFileName.equals("kar")) {
contentType = "audio/midi";
} else if (returnFileName.equals("mp3")) {
contentType = "audio/mpeg";
} else if (returnFileName.equals("ogg")) {
contentType = "audio/ogg";
} else if (returnFileName.equals("m4a")) {
contentType = "audio/x-m4a";
} else if (returnFileName.equals("ra")) {
contentType = "audio/x-realaudio";
} else if (returnFileName.equals("3gpp")
|| returnFileName.equals("3gp")) {
contentType = "video/3gpp";
} else if (returnFileName.equals("mp4")) {
contentType = "video/mp4";
} else if (returnFileName.equals("mpeg")
|| returnFileName.equals("mpg")) {
contentType = "video/mpeg";
} else if (returnFileName.equals("mov")) {
contentType = "video/quicktime";
} else if (returnFileName.equals("flv")) {
contentType = "video/x-flv";
} else if (returnFileName.equals("m4v")) {
contentType = "video/x-m4v";
} else if (returnFileName.equals("mng")) {
contentType = "video/x-mng";
} else if (returnFileName.equals("asx") || returnFileName.equals("asf")) {
contentType = "video/x-ms-asf";
} else if (returnFileName.equals("wmv")) {
contentType = "video/x-ms-wmv";
} else if (returnFileName.equals("avi")) {
contentType = "video/x-msvideo";
}

return contentType;
}
}

http断点下载客户端和服务端的更多相关文章

  1. Java 断点下载(下载续传)服务端及客户端(Android)代码

    原文: Java 断点下载(下载续传)服务端及客户端(Android)代码 - Stars-One的杂货小窝 最近在研究断点下载(下载续传)的功能,此功能需要服务端和客户端进行对接编写,本篇也是记录一 ...

  2. 网络编程 UDP协议 TCP局域网客户端与服务端上传下载电影示例

    UDP协议 (了解) 称之为数据包协议,又称不可靠协议. 特点: 1) 不需要建立链接. 2) 不需要知道对方是否收到. 3) 数据不安全 4) 传输速度快 5)能支持并发 6) 不会粘包 7) 无需 ...

  3. Java实现UDP之Echo客户端和服务端

    Java实现UDP之Echo客户端和服务端 代码内容 采用UDP协议编写服务器端代码(端口任意) 编写客户机的代码访问该端口 客户机按行输入 服务器将收到的字符流和接收到的时间输出在服务器consol ...

  4. Java实现TCP之Echo客户端和服务端

    Java实现TCP之Echo客户端和服务端 代码内容 采用TCP协议编写服务器端代码(端口任意) 编写客户机的代码访问该端口 客户机按行输入 服务器将收到的字符流和接收到的时间输出在服务器consol ...

  5. WCF 客户端与服务端消息传输

    WCF很多需要认证信息,保证服务的安全,可以使用消息来实现 WCF 实现消息的方式: WCF中有两个接口: IClientMessageInspector [定义一个消息检查器对象,该对象可以添加到 ...

  6. Android BLE与终端通信(三)——客户端与服务端通信过程以及实现数据通信

    Android BLE与终端通信(三)--客户端与服务端通信过程以及实现数据通信 前面的终究只是小知识点,上不了台面,也只能算是起到一个科普的作用,而同步到实际的开发上去,今天就来延续前两篇实现蓝牙主 ...

  7. Axis创建webservice客户端和服务端

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本人声明.否则将追究法律责任. 作者:永恒の_☆ 地址:http://blog.csdn.net/chenghui0317/ ...

  8. java客户端与服务端交互通用处理 框架解析

    一.综述 java 客户端与服务端交互过程中,采用NIO通讯是异步的,客户端基本采用同一处理范式,来进行同异步的调用处理. 处理模型有以下几个要素: 1. NIO发送消息后返回的Future 2. 每 ...

  9. 安装_oracle11G_客户端_服务端_链接_oracle

    在开始之前呢,有一些注细节需要注意,oracle11G_客户端_和_服务端, 分为两种   一种是  开发者使用    一种是  BDA  自己使用(同时也需要根据自己 PC 的系统来做_win7_与 ...

随机推荐

  1. Java泛型的PECS原则

    1.什么是PESC ? PESC  = producer-extens , consumer -super. 如果参数化类型表示一个 T 生产者,就使用 <? extends T>: 如果 ...

  2. HttpServletRequest对象(一)

    javaweb学习总结(十)——HttpServletRequest对象(一) 一.HttpServletRequest介绍 HttpServletRequest对象代表客户端的请求,当客户端通过HT ...

  3. 转 CentOS下php安装mcrypt扩展

    (以下步骤均为本人实际操作,可能与你的安装方法有所区别,但我会尽量排除疑惑) 大致步骤(1)安装mcrypt,(2)安装php对mcrypt的扩展,(3)重启apache (1).确认你的linux没 ...

  4. 《web与移动开发》征文活动

    活动简介: 首次征文活动有PHPChina主办,是面向全国所有的IT界活动,希望大家大家以PHPChina论坛为载体,积极的分享技术.希望技术的分享为大家的工作猪跑,也希望大家早日成为技术行业的中流砥 ...

  5. 转:折腾一晚上Bullet及Ogre相关工具的成果 -- 3Ds Max,Maya, blender, GameKit

    起始目的很简单,整合Bullet及Ogre,找个能够生成.scene和.bullet文件的建模工具. 折腾一晚上Bullet及Ogre相关的东西,基本上就像爱迪生发明灯泡一样,得出了N个失败的教训,总 ...

  6. Windows开发进阶之VC++中如何实现对话框的界面重绘

    技术:Windows 系统+Visual studio 2008   概述 应用程序界面是用户与应用程序之间的交互的桥梁和媒介,用户界面是应用程序中最重要的组成部分,也是最为直观的视觉体现.对用户而言 ...

  7. Java交替打印两个字符串

    一.使用volatile关键字 public class Main { volatile int x = 0; Main() { new Thread(() -> { while (x < ...

  8. 由m种数字组成的n位数有多少个

    知乎链接 问题描述 我和我女朋友的QQ号都是九位数字,这九个数字是有七个不同的数字组成的,我想问这种概率是多大,我们是不是特别我看缘分呢?求大神给算一下概率! 思路 定义问题:由7种数字组成的9位数一 ...

  9. 【LeetCode】Missing Ranges

    Missing Ranges Given a sorted integer array where the range of elements are [lower, upper] inclusive ...

  10. 【Algorithm】回溯法与深度优先遍历的异同

    1.相同点: 回溯法在实现上也是遵循深度优先的,即一步一步往前探索,而不像广度优先那样,由近及远一片一片地扫. 2.不同点 (1)访问序 深度优先遍历: 目的是“遍历”,本质是无序的.也就是说访问次序 ...