C#编程总结(十二)断点续传

我们经常使用下载工具,如bit精灵、迅雷、FlashGet,这些软件都支持断点续传。

断点续传即下载任务暂停后可以继续,而无需重新下载,即下载时需要通知服务器的起始位置。如果允许多线程进行分片下载,必须提供起始-截止位置。说到底就是可以选择下载某个片段,整个文件的字节流,可以截取流的片段,也能实现流的累积,最终完成文件下载。

一、原理

在 HTTP/1.1里新增的一个头属性:Range,也是现在众多号称多线程下载工具(如 FlashGet、迅雷等)实现多线程下载的核心所在。老版本的HTTP协议不支持,所以一些老的服务器还不支持断点续传。

Range(请求参数)

用于请求头中,指定第一个字节的位置和最后一个字节的位置,一般格式:

Range:(unit=first byte pos)-[last byte pos]

例如:Range:100-199,取文件流的100至199之间的字节。

Range:100,取位置为100后的所有字节。如果range 为正值,服务器应该开始发送从指定的 range 参数到 HTTP 实体中数据的末尾之间的数据。

Range:-99,取开始的100个字节。如果range 为负值,服务器应该开始发送从 HTTP 实体中数据的开头到指定的 range 参数之间的数据。

Content-Range (响应参数)

用于响应头,指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度。

一般格式:   

Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth] 

例如:Content-Range: bytes 1024000-1126399/7421120

HTTP协议:http://www.w3.org/Protocols/rfc2616/rfc2616.html

二、C#中实现

在C#中使用AddRange方法向请求添加指定范围的字节范围标头

System.Net.HttpWebRequest

所有的方法:

常用的方法为例:

void AddRange(long from, long to);
指定范围起始、终止位置,来请求该片段的数据。
        // 摘要:
// 向请求添加指定范围的字节范围标头。
//
// 参数:
// from:
// 开始发送数据的位置。
//
// to:
// 停止发送数据的位置。
public void AddRange(long from, long to);

我们通过该方法,基于HTTP协议实现了断点续传,支持暂停、继续下载功能,为了更清晰显示效果,提供了进度条显示。效果图:

Request

请求的Range参数,我们可以清晰看到起具体值,这就是请求的片段。在这里可以清晰的看到HTTP协议版本、请求方法、请求地址等信息

Response

服务器根据请求的Range参数,只返回该片段的数据。我们可以清晰看到Content-Range的具体值。

注意:返回的StatusCode变为了PartialContent,说明是部分数据。

代码 含义
200 OK     请求成功返回
206 Partial Content     部分数据

 下载的核心代码:

        /// <summary>
/// 下载
/// </summary>
public void Download()
{
//从0计数,需要减一
long from = this.currentSize;
if (from < )
{
from = ;
} long to = this.currentSize + this.step - ;
if (to >= this.totalSize && this.totalSize > )
{
to = this.totalSize - ;
}
this.Download(from, to);
}
/// <summary>
/// 下载
/// </summary>
/// <param name="url"></param>
/// <param name="range"></param>
public void Download(long from,long to)
{
if (this.totalSize == )
{
GetTotalSize();
}
if (from >= this.totalSize || this.currentSize >= this.totalSize)
{
this.isFinished = true;
return;
} HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
//request.Method = "GET";
request.AddRange("bytes", from, to); HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string result = string.Empty;
if (response != null)
{
byte[] buffer = this.Buffer;
using (Stream stream = response.GetResponseStream())
{
int readTotalSize = ;
int size = stream.Read(buffer, , buffer.Length);
while (size > )
{
//只将读出的字节写入文件
fs.Write(buffer, , size);
readTotalSize += size;
size = stream.Read(buffer, , buffer.Length);
} //更新当前进度
this.currentSize += readTotalSize; //如果返回的response头中Content-Range值为空,说明服务器不支持Range属性,不支持断点续传,返回的是所有数据
if (response.Headers["Content-Range"] == null)
{
this.isFinished = true;
}
}
}
}

项目源码:

http://files.cnblogs.com/yank/DownloadSample.rar

三、多线程下载

上述例子提供了简单的断点续传功能,如果想再进一步实现多线程下载。原理很简单,我们只需根据所要下载的文件大小,进行分块,没块启动一个线程进行下载,线程只负责下载自己负责的片段,一定要严格设置Range的值。具体实现这里不再介绍,如有兴趣,下来可以继续研究。

提醒一下:多线程下载的字节流如何保存为文件,是否必须按照先后顺序?

C#编程总结(十二)断点续传的更多相关文章

  1. 学习ASP.NET Core Razor 编程系列十二——在页面中增加校验

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  2. 通过Socket实现TCP编程(十二)

    原文链接:https://www.cnblogs.com/hysum/p/7531529.html Socket通信 : TCP协议是面向对象连接.可靠的.有序的,以字节流的方式发送数据. 基于TCP ...

  3. 【读书笔记】C#高级编程 第二十二章 安全性

    (一)身份验证和授权 安全性的两个基本支柱是身份验证和授权.身份验证是标识用户的过程,授权在验证了所标识用户是否可以访问特性资源之后进行的. 1.标识和Principal 使用标识可以验证运行应用程序 ...

  4. 并发编程(十二)—— Java 线程池 实现原理与源码深度解析 之 submit 方法 (二)

    在上一篇<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法.这篇文章是接着上一篇文章 ...

  5. Linux网络编程学习(十二) ----- 结语

    该书提前看完了,重点看了第四章和第六章,第七章以后只是大致浏览了一下,如果以后工作中涉及这一块再仔细研究一下,大概花了二十天的样子,主要了解了进程间的通信方式.socket编程以及五种I/O模式,看的 ...

  6. Java并发编程(十二)Callable、Future和FutureTask

    一.Callable与Runnable 先说一下java.lang.Runnable吧,它是一个接口,在它里面只声明了一个run()方法: public interface Runnable { pu ...

  7. 【读书笔记】C#高级编程 第十二章 动态语言扩展

    (一)DLR C#4的动态功能是Dynamic Language Runtime(动态语言运行时,DLR)的一部分.DLR是添加到CLR的一系列服务. (二)dynamic类型 dynamic类型允许 ...

  8. java 面向对象编程 --第十二章 JDK常用类

    1.  系统类 java.lang包   System类 sys.out;sys.exit;sys.gc; sys.currentTimeMillis();----得到从1970-01-01到当前时间 ...

  9. Java并发编程(十二)-- 阻塞队列

    在介绍Java的阻塞队列之前,我们简单介绍一下队列. 队列 队列是一种数据结构.它有两个基本操作:在队列尾部加人一个元素,和从队列头部移除一个元素就是说,队列以一种先进先出的方式管理数据,如果你试图向 ...

  10. python系统编程(十二)

    异步 同步调用就是你 喊 你朋友吃饭 ,你朋友在忙 ,你就一直在那等,等你朋友忙完了 ,你们一起去 异步调用就是你 喊 你朋友吃饭 ,你朋友说知道了 ,待会忙完去找你 ,你就去做别的了. from m ...

随机推荐

  1. Android 数据传递(二)Activity与fragment之间的通信

    在网上找到了一篇总结的非常好的文章,我这里就贴出他的博文地址.自己就不再写这个方面的总结了. Activity与Fragment通信(99%)完美解决方案

  2. Atitit 图片 验证码生成attilax总结

    Atitit 图片 验证码生成attilax总结 1.1. 图片验证码总结1 1.2. 镂空文字  打散 干扰线 文字扭曲 粘连2 1.1. 图片验证码总结 因此,CAPTCHA在图片验证码这一应用点 ...

  3. salesforce 零基础学习(三十)工具篇:Debug Log小工具

    开发中查看log日志是必不可少的,salesforce自带的效果显示效果不佳,大概显示效果如下所示: chrome商城提供了apex debug log良好的插件,使debug log信息更好显示.假 ...

  4. php使用正则过滤js脚本代码实例

    匹配的规则不能用 "/<script.*<\/script>/i",因为它不能匹配到换行符,那么多行js就匹配不掉了. 要用 "/<script[ ...

  5. CCNA网络工程师学习进程(1)网络的基本概述

        在互联网快速发展的今天,了解互联网成为一项必须的技能,因此在学习编程之余学习如何配置网络还是很有必要的. 本系列博客计划分为三个部分,包括思科CCNA.CCNP和华为的网络工程师认证有关的知识 ...

  6. Zookeeper-Zookeeper启动过程

    在上一篇,我们了解了zookeeper最基本的配置,也从中了解一些配置的作用,那么这篇文章中,我们将介绍Zookeeper的启动过程,我们在了解启动过程的时候还要回过头看看上一篇中各个配置参数在启动时 ...

  7. Oracle参数篇

    1. ARCHIVE_LAG_TARGET forces a log switch after the specified amount of time elapses.有效值为0(disabled) ...

  8. LSA,pLSA原理及其代码实现

    一. LSA 1. LSA原理 LSA(latent semantic analysis)潜在语义分析,也被称为 LSI(latent semantic index),是 Scott Deerwest ...

  9. Anliven - 有效阅读的方法

    讲方法,忌盲目. 阅读方法 做好眼前事 排除其他事项干扰,营造适合阅读的状态和环境,专注地投入阅读之中. 如果被一堆乱糟糟的事情烦扰,身心处于一个疲惫的状态,必然无法保持专注的阅读. 定性定量 每个人 ...

  10. 使用 CSS3 伪元素实现立体的照片堆叠效

    CSS3 里引入的伪元素让 Web 开发人员能够在不需要额外添加 HTML 标签的情况下制作出复杂的视觉效果.例如,:before 和 :after 这个两个 CSS3 伪元素就可以帮助你实现很多有趣 ...