客户端;
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. android openCL的so库目录(转)

    android 6.0下 高通平台:/system/vendor/lib/libOpenCL.so mali:/system/lib/egl/libGLES_mali.so 在应用市场上下载openC ...

  2. cocos2d-js 写日志log 查看日志log Android调试查看log

    1 输出日志的方式,当然是cc.log了 2 如何查看日志?        a)如果小程序可以先在浏览器上跑,例如用chrome,在控制台就可以看到输出的log:        b)如果在真机上调试, ...

  3. yii框架的部署方法

    yii框架(yii framework)的部署方法 刚開始学习的人来说,部署yii框架还是有一定难度的,Yii是一个基于组件.用于开发大型 Web 应用的高性能 PHP 框架.Yii提供了今日Web ...

  4. 转 CentOS下php安装mcrypt扩展

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

  5. 2011的n次方

    题目:http://noi.openjudge.cn/ch0204/2991/ 总时间限制:1000ms  内存限制: 65536kB 描述 已知长度最大为200位的正整数n,请求出2011^n的后四 ...

  6. 开源通用型渲染工具-SwiftShader--OpenGL的替代者

    SwiftShader 是一款用于在 CPU 上进行高性能图形渲染的软件库.Google 已经在很多产品中使用该内容库,包括 Chrome.Android 开发工具和云服务.Swiftshader 从 ...

  7. resume.c

    resume.c //采用CURLOPT_RESUME_FROM_LARGE 实现文件断点续传功能 #include <stdlib.h> #include <stdio.h> ...

  8. 使用 WM_COPYDATA 在进程间共享数据

    开发中有时需要进程间传递数据,比如对于只允许单实例运行的程序,当已有实例运行时,再次打开程序,可能需要向当前运行的实例传递信息进行特殊处理.对于传递少量数据的情况,最简单的就是用SendMessage ...

  9. php如何在某个时间上加一天?一小时? 时间加减(转)

    <?php date_default_timezone_set('PRC'); //默认时区 echo "今天:",date("Y-m-d",time() ...

  10. 将windows目录共享到linux

    1.将windows目录共享 2.安装cifs 3.  mount -t cifs -o username=电脑登陆用户名,password=电脑登陆用户密码 //127.0.0.1/abc /var ...