基于HTTP协议的下载功能实现
超文本传输协议 (HTTP-HyperText Transfer Protocol)是一种使用极为广泛的协议,它由请求和响应构成,是一种无状态的应用层协议。设计HTTP协议的初衷是为了提供一种传输HTML(HyperText Markup Language,超文本标记语言)的协议和方法。通过HTTP协议请求的资源由URI(Uniform Resource Identifiers,统一资源标识符)来标识。通常,我们通过URI就能访问到万维网服务器提供的数据,如HTML文档、音视频等各种格式的数据。因此,基于HTTP协议,我们可以实现简单的下载器功能。
HTTP下载器的功能很简单,下载器使用指定的URI发送GET请求到服务器,服务器返回请求响应,下载器根据响应状态码判断请求成功与否。一般情况下,请求一个资源成功后的状态码应为200(HTTP_OK)或者206(Partial-Content)。其他状态码视为失败(具体的HTTP状态码请参见:http://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81)。若请求成功,HTTP响应头中将会带有资源的相关信息,其中,我们最关心的是资源大小,一般以Content-Length字段返回(HTTP头字段请参考:http://msdn.microsoft.com/zh-cn/library/aa287673(v=vs.71).aspx),若有Range字段的情况下,也可以通过Range字段的返回值来计算得到资源的大小,这里的资源大小单位为byte。
下面就以Java语言来实现一个基于HTTP协议的下载器。因测试工程是为项目所编写,实现了一套完整的下载管控机制(如下载记录管理、多任务管理、断点续下、意外中断自动恢复下载、状态通知等功能),为保密起见,以下只公开下载部分核心代码:
下载状态类:
public class Status {
public static final int ERROR = -1; public static final int WAITING = 0; /**
* Paused by system automatically
*/
public static final int PAUSED = 1; /**
* Paused by user manually
*/
public static final int PAUSED_MANUALLY = 2; public static final int DOWNLOADING = 3; public static final int FINISHED = 4;
}
下载类:
package com.irwin.downloader; import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL; import org.apache.http.HttpStatus; public class Downloader implements Runnable {
private static final int BUFFER_SIZE = 32 * 1024; private String mUrl = null; private String mPath = null; private long mStart = 0; private long mCurrentBytes = 0; private int mStatus = Status.WAITING; private long mSize = 0; private boolean mRunning = true; private boolean mTerminate = false; public void setUrl(String url) {
mUrl = url;
} public String getUrl() {
return mUrl;
} public void setPath(String path) {
mPath = path;
} public String getPath() {
return mPath;
} public void setRange(long start, long end) {
if (start >= 0) {
mStart = start;
}
mSize = end;
} public void setTerminate(boolean terminate) {
mTerminate = terminate;
} public boolean isRunning() {
return mRunning;
} public int getStatus() { return mStatus;
} public long getSize() {
return mSize;
} public long getCurrentBytes() {
return mCurrentBytes;
} public void download(String url, String path, long rangeStart)
throws Exception {
if (rangeStart > 0 && rangeStart >= mSize) {
mStatus = Status.FINISHED;
return;
}
InputStream inStream = null;
RandomAccessFile file = null;
try {
URL downUrl = new URL(url);
HttpURLConnection http = (HttpURLConnection) downUrl
.openConnection();
http.setConnectTimeout(5 * 1000);
//Use Get method
http.setRequestMethod("GET");
//Accept all format of data.
http.setRequestProperty("Accept", "*/*");
http.setRequestProperty("Charset", "UTF-8"); //Data block to download.
http.setRequestProperty("Range", "bytes=" + rangeStart + "-");
http.setRequestProperty("User-Agent", "Client/4.0");
http.setRequestProperty("Connection", "Keep-Alive");
http.connect();
if (http.getResponseCode() != HttpStatus.SC_OK
&& http.getResponseCode() != HttpStatus.SC_PARTIAL_CONTENT) {
throw new IllegalAccessException("Invalid request: "
+ http.getResponseCode());
}
if (mSize <= 0) {
long total = getContentLen(http); if (total <= 0) {
throw new IllegalAccessException("Invalid content-length: "
+ total);
}
mSize = total;
}
mStatus = Status.DOWNLOADING;
inStream = http.getInputStream();
byte[] buffer = new byte[BUFFER_SIZE];
File tmp=new File(path+".tmp");
file = new RandomAccessFile(tmp, "rwd");
file.setLength(mSize);
file.seek(rangeStart);
int offset = 0;
mCurrentBytes = rangeStart;
while (true) {
if (mTerminate) {
mStatus = Status.PAUSED_MANUALLY;
break;
}
if ((offset = inStream.read(buffer)) != -1) {
file.write(buffer, 0, offset);
mCurrentBytes += offset;
} else {
break;
}
} file.close();
file = null;
inStream.close();
inStream = null;
if (mSize == mCurrentBytes) {
// Rename
mStatus = Status.FINISHED;
File f = new File(path);
tmp.renameTo(f);
} } catch (Exception e) {
throw e;
} finally {
if (inStream != null) {
try {
inStream.close();
} catch (Exception e2) {
// TODO: handle exception
}
}
if (file != null) {
try {
file.close();
} catch (Exception e2) {
// TODO: handle exception
}
}
}
} @Override
public void run() {
if (getUrl() != null && getPath() != null) {
if (!mTerminate) {
try {
download(getUrl(), getPath(), mStart);
} catch (Exception e) {
e.printStackTrace();
mStatus = Status.ERROR;
}
}
} else {
mStatus = Status.ERROR;
}
mRunning = false;
} private long getContentLen(HttpURLConnection conn) throws Exception {
long len = conn.getContentLength();
if (len <= 0) {
try {
len = Long.parseLong(conn.getHeaderField("Content-Length"));
} catch (Exception e) {
// TODO: handle exception
} }
if (len <= 0) {
//Try to calculate size from 'Range' field.
String range = conn.getHeaderField("Range");
if (range != null) {
String[] array = range.replace("bytes=", "").split("-");
if (array.length == 2) {
len = Long.parseLong(array[1]) - Long.parseLong(array[0]);
}
}
}
return len;
}
}
更多代码详情请参考:TransferLibrary——一个Android文件传输库,主要实现基于Http的文件上传和下载,简单方便,支持多任务下载,断点续传等等,欢迎小伙伴们使用交流:D
基于HTTP协议的下载功能实现的更多相关文章
- Android之基于HTTP协议的下载
Android之基于HTTP协议的下载 http://www.blogjava.net/zh-weir/archive/2010/05/02/319892.html http://www.qianfa ...
- Android之基于HTTP协议的通信详解
Android系统中本身是有下载机制的,比如浏览器使用的DownloadManager.可遗憾的是,DownloadManager只提供给浏览器使用,一般的应用程序没法调用它. 另外,如果下载调用频繁 ...
- RPC基于http协议通过netty支持文件上传下载
本人在中间件研发组(主要开发RPC),近期遇到一个需求:RPC基于http协议通过netty支持文件上传下载 经过一系列的资料查找学习,终于实现了该功能 通过netty实现文件上传下载,主要在编解码时 ...
- 转:【专题十一】实现一个基于FTP协议的程序——文件上传下载器
引言: 在这个专题将为大家揭开下FTP这个协议的面纱,其实学习知识和生活中的例子都是很相通的,就拿这个专题来说,要了解FTP协议然后根据FTP协议实现一个文件下载器,就和和追MM是差不多的过程的,相信 ...
- 实现基于NTP协议的网络校时功能
无论PC端还是移动端系统都自带时间同步功能,基于的都是NTP协议,这里使用C#来实现基于NTP协议的网络校时功能(也就是实现时间同步). 1.NTP原理 NTP[Network Time Protoc ...
- 专题十一:实现一个基于FTP协议的程序——文件上传下载器
引言: 在这个专题将为大家揭开下FTP这个协议的面纱,其实学习知识和生活中的例子都是很相通的,就拿这个专题来说,要了解FTP协议然后根据FTP协议实现一个文件下载器,就和和追MM是差不多的过程的,相信 ...
- 基于HTTP协议下载文件的实现
最近在开发文件下载的程序,该程序是基于HTTP开发的. 首先是了解了文件传输到客户端的大概格式,然后分析该格式,实现写入文件的功能. 自己构造的HTTP包如下: GET /*********.rar ...
- 用c++开发基于tcp协议的文件上传功能
用c++开发基于tcp协议的文件上传功能 2005我正在一家游戏公司做程序员,当时一直在看<Windows网络编程> 这本书,把里面提到的每种IO模型都试了一次,强烈推荐学习网络编程的同学 ...
- Android消息推送(二)--基于MQTT协议实现的推送功能
国内的Android设备,不能稳定的使用Google GCM(Google Cloud Messageing)消息推送服务. 1. 国内的Android设备,基本上从操作系统底层开始就去掉了Googl ...
随机推荐
- 如何安装Elasticsearch?
最近工作中要用到搜索引擎,由于目前用的搜索引擎是LeanCloud 提供的 ,不太好用,不支持范围等搜索,而且每天还收费30元,请求次数也有限制.基于这些原因,我们只好在自己的服务器上部署搜索引擎了. ...
- Java中 EvenQueue.invokeLater用法
在Java中Swing是线程不安全的,是单线程的设计,这样的造成结果就是:只能从事件派发线程访问将要在屏幕上绘制的Swing组件.事件派发线程是调用paint和update等回调方法的线程,它还是事件 ...
- 关于Cookie安全性设置的那些事
一.标题:关于Cookie安全性设置的那些事 副标:httponly属性和secure属性解析 二.引言 经常有看到XSS跨站脚本攻击窃取cookie案例,修复方案是有httponly.今天写出来倒腾 ...
- struts2.1.6教程四_2、ActionContext 、ValueStack 、Stack Context
ActionContext 一次Action调用都会创建一个ActionContext 调用:ActionContext context = ActionContext.getContext() Va ...
- 开涛spring3(6.7) - AOP 之 6.7 通知顺序
如果我们有多个通知想要在同一连接点执行,那执行顺序如何确定呢?Spring AOP使用AspectJ的优先级规则来确定通知执行顺序.总共有两种情况:同一切面中通知执行顺序.不同切面中的通知执行顺序. ...
- 使用ThreadLocal实现的读写分离在迁移后的偶发错误
最近莫名的会有错误日志,说有写操作因为走了读库而报了read only的异常,由于并没有造成应用使用的问题,开始我以为哪的配置错误就没当回事让程序员自己去查了,然而... 背景:之前的博客里提到过,读 ...
- springboot 1.5.2 集成kafka 简单例子
添加依赖 compile("org.springframework.kafka:spring-kafka:1.1.2.RELEASE") 添加application.propert ...
- LinkedList源码解读
一.内部类Node数据结构 在讲解LinkedList源码之前,首先我们需要了解一个内部类.内部类Node来表示集合中的节点,元素的值赋值给item属性,节点的next属性指向下一个节点,节点的pre ...
- 【二】python内置类型
1.布尔类型 表示真假的类型(true和false) 数字 0.None,以及元素为空的容器类对象都可视作False,反之为 True. In [1]: bool(0) Out[1]: False I ...
- Eclipse导入项目常见问题----乱码问题03
有时打开导入的项目文件时,会出现如下图情况: 解决方法 如下图步骤所示: 此时,我们可以看到文件正常了 jdk版本问题(有个红色感叹号)01:http://blog.csdn.net/baidu_37 ...