c# 断点续传的实现

作者:sparkdev
出处:http://www.cnblogs.com/sparkdev/

注意,本文所说的断点续传特指 HTTP 协议中的断点续传。本文主要聊聊思路和关键代码,更多细节请参考本文附带的 demo。

工作原理

HTTP 协议中定义了一些请求/响应头,通过组合使用这些头信息。我们可以在一次 HTTP 请求中只请求一个文件中的一部分数据。这样我们就可以把已经下载的数据存起来,下次只用请求剩余的数据即可,当全部数据都下载到本地后再完成合并工作。

HTTP 协议指出,可以通过 HTTP 请求中的 Range 头指定请求数据的范围,Range 头的使用也很简单,只要指定下面的格式就可以了:

Range: bytes=500-999

它的意思是,只请求目标文件的第 500 到第 999 这 500 个字节。

比如我有一个1000 bytes 大小的文件需要下载,第一次请求时不用指定 Range 头,表示下载整个文件。但在下载完第 499 个字节后,下载被取消了。那么在下一次请求下载同一个文件时,只需要下载第 500 个字节至第 999 个字节的数据就可以了。原理看上去很简单,但我们需要考虑下面几个问题:

1.    是不是所有的 web 服务器都支持 Range 头?
2.    多次请求之间可能会间隔很长的时间,服务器上的文件发生了变化怎么办?
3.    如何保存下载的部分数据和相关信息?
4.    当我们通过字节操作把一个文件拼成原始大小后,如何验证它和源文件一模一样?

下面我们就带着这些问题去探究断点续传的一些细节。

检查服务器端对断点续传的支持

在服务器响应我们的请求时,会在响应头中通过 Accept-Ranges 指明是否接受请求一个资源的一部分数据。但这里似乎有个小小的陷阱,就是不同的服务器可能返回不同的值来指明自己能够接受部分资源的请求。貌似比较统一的方法是,当服务器不支持请求部分数据时,都会返回 Accept-Ranges: none,我们只要判断这个返回值是不是等于 none 就行了。代码如下:

private static bool IsAcceptRanges(WebResponse res)
{
  if (res.Headers["Accept-Ranges"] != null)
  {
    string s = res.Headers["Accept-Ranges"];
    if (s == "none")
    {
      return false;
    }
  }
  return true;
}

检查服务器端文件是否变化

当我们下载了一个文件的一部分之后,可能马上就会接着下载,也可能会过一段时间再下载,也可能永远不会再接着下载了…
这里的问题是,当下次要接着下载时,如何确定服务器上的文件还是当初下载了一半的那个文件。如果服务器上的文件已经更新了,那无论如何都需要重新从头开始下载。只有在服务器上的文件没有发生变化的情况下,断点续传才有意义。
对于这个问题,HTTP 响应头为我们提供了不同的选择。ETag 和 Last-Modified 都能完成任务。

先看 ETag:

The ETag response-header field provides the current value of the entity tag for the requested variant. (引自RFC2616 14.19 ETag)
简单点说 ETag 就是一个标识当前请求内容的字符串,当请求的资源发生变化后,对应的 ETag 也会变化。好了,最简单的办法是第一次请求时,把响应头中的 ETag 存下来,下次请求时做比较。代码如下:

string newEtag = GetEtag(response);
// tempFileName指已经下载到本地的部分文件内容
// tempFileInfoName指保存了Etag内容的临时文件
if (File.Exists(tempFileName) && File.Exists(tempFileInfoName))
{
  string oldEtag = File.ReadAllText(tempFileInfoName);
  if (!string.IsNullOrEmpty(oldEtag) && !string.IsNullOrEmpty(newEtag) && newEtag == oldEtag)
  {
  // Etag没有变化,可以断点续传
    resumeDowload = true;
  }
}
else
{
  if (!string.IsNullOrEmpty(newEtag))
  {
    File.WriteAllText(tempFileInfoName, newEtag);
  }
}
private static string GetEtag(WebResponse res)
{
  if (res.Headers["ETag"] != null)
  {
    return res.Headers["ETag"];
  }
  return null;
}

再来看看 Last-Modified:

The Last-Modified entity-header field indicates the date and time at which the origin server believes the variant was last modified. (引自RFC2616 14.29 Last-Modified)
Last-Modified 就是所请求的资源在服务器上的最后一次修改时间。使用方法和 ETag 大体相同。

个人感觉使用 ETag 和 Last-Modified 中的任何一个都能达到我们的目的。但是你也可以两个都用,做 double check,谁知道web服务器的实现是不是严格遵循了 HTTP 协议!

保存中间结果

这里主要就是用 C# 进行文件操作。大体思路是如果有未下载完的文件,就把新下载的字节添加到文件的末尾,不再啰嗦,有兴趣的同学请直接看 demo 代码。

验证文件

在断点续传的过程中,我们以 byte 为单位下载、合并文件,如果整个过程中稍有没有处理好的异常,可能最后得到的文件就和源文件不太一样。因此最好是能够对下载好的文件进行一次校验。可这也是最难、最不容易实现的。因为它需要服务器端的支持,比如服务器端在提供一个可下载文件的同时提供该文件的 MD5 hash。当然,如果服务器端也是我们自己创建的,我们就可以去实现它。但我们又怎么能够要求现存的 web 服务器都提供这样的功能呢!

demo

以上就是c# 断点续传的实现的详细内容,更多关于c# 断点续传的资料请关注我们其它相关文章!

(0)

相关推荐

  • C#实现文件断点续传下载的方法

    本文实例讲述了C#实现文件断点续传下载的方法.分享给大家供大家参考.具体实现方法如下: using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.IO; using System.Text; using System.Net; namespace simpleDemo { class Program { /// <su

  • c#实现断点续传功能示例分享

    在了解HTTP断点续传的原理之前,让我们先来了解一下HTTP协议,HTTP协议是一种基于tcp的简单协议,分为请求和回复两种.请求协议是由客户机(浏览器)向服务器(WEBSERVER)提交请求时发送报文的协议.回复协议是由服务器(webserver),向客户机(浏览器)回复报文时的协议.请求和回复协议都由头和体组成.头和体之间以一行空行为分隔. 以下是一个请求报文与相应的回复报文的例子: 复制代码 代码如下: GET /image/index_r4_c1.jpg HTTP/1.1Accept:

  • C# FileStream实现多线程断点续传

    一.前言 网上有许多的多线程断点续传操作,但总是写的很云里雾里,或者写的比较坑长.由于这几个月要负责公司的在线升级项目,所以正好顺便写了一下 代码如下: using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; namespace TestCenter { class Program { static void Main(string[] args) { strin

  • C# 文件下载之断点续传实现代码

    注意,本文所说的断点续传特指 HTTP 协议中的断点续传.本文主要聊聊思路和关键代码,更多细节请参考本文附带的 demo. 工作原理 HTTP 协议中定义了一些请求/响应头,通过组合使用这些头信息.我们可以在一次 HTTP 请求中只请求一个文件中的一部分数据.这样我们就可以把已经下载的数据存起来,下次只用请求剩余的数据即可,当全部数据都下载到本地后再完成合并工作. HTTP 协议指出,可以通过 HTTP 请求中的 Range 头指定请求数据的范围,Range 头的使用也很简单,只要指定下面的格式

  • C#文件断点续传实现方法

    本文实例讲述了C#文件断点续传实现方法.分享给大家供大家参考.具体实现方法如下: /// <summary> /// 下载局域网文件 /// </summary> /// <param name="path">文件路径,如:\\192.168.10.1\app\app\123.zip</param> /// <param name="username">计算机名称</param> /// <

  • C#实现支持断点续传多线程下载客户端工具类

    复制代码 代码如下: /* .Net/C#: 实现支持断点续传多线程下载的 Http Web 客户端工具类 (C# DIY HttpWebClient) * Reflector 了一下 System.Net.WebClient ,改写或增加了若干: * DownLoad.Upload 相关方法! * DownLoad 相关改动较大! * 增加了 DataReceive.ExceptionOccurrs 事件! * 了解服务器端与客户端交互的 HTTP 协议参阅: * 使文件下载的自定义连接支持

  • Asp.net中断点续传的原理与实现方法分享

    请求协议是由客户机 (浏览器)向服务器(WEB SERVER)提交请求时发送报文的协议.回复协议是由服务器(web server),向客户机(浏览器)回复报文时的协议.请求和回复协议都由头和体组成.头和体之间以一行空行为分隔. 以下是一个请求报文与相应的回复报文的例子: 复制代码 代码如下: GET /image/index_r4_c1.jpg HTTP/1.1 Accept: */* Referer: http://192.168.3.120:8080 Accept-Language: zh-

  • iOS11 下载之断点续传的bug的解决方法

    iOS11发布之后,可能很多带有下载功能的APP都会躺枪(ps:埋怨苹果爸爸几秒钟).因为原先用来做断点续传的resumeData里带上了一个新值,而这个新值的出现,会导致几次暂停操作后下载任务task读取数据不对,而且在文件还没下载完时就会调用下载完成时的代理方法,导致下载出错.下面就来说说解决的办法. 第一种方法:暂停时不调用[task cancelByProducingResumeData:^(NSData *resumeData){ }];而是调用suspend线程挂起的方法,可解决这个

  • java实现文件断点续传下载功能

    本文实例为大家分享了java断点续传下载的代码,供大家参考,具体内容如下 1. Java代码     //实现文件下载功能 public String downloadFile(){ File dir = new File(filepath);//获取文件路劲 if(!dir.exists()) { System.out.println("文件路径错误"); log.debug("文件路径错误"); return "failed";// 判断文件

  • iOS开发网络编程之断点续传

    前言 网络下载是我们在项目中经常要用到的功能,如果是小文件的下载,比如图片和文字之类的,我们可以直接请求源地址,然后一次下载完毕.但是如果是下载较大的音频和视频文件,不可能一次下载完毕,用户可能下载一段时间,关闭程序,回家接着下载.这个时候,就需要实现断点续传的功能.让用户可以随时暂停下载,下次开始下载,还能接着上次的下载的进度. 今天我们来看看如何自己简单的封装一个断点续传的类,实现如下功能. 1.使用者只需要调用一个接口即可以下载,同时可以获取下载的进度. 2.下载成功,可以获取文件存储的位

  • PHP实现下载断点续传的方法

    本文实例讲述了PHP实现下载断点续传的方法.分享给大家供大家参考. 具体实现代码如下: 复制代码 代码如下: <?php /*  * PHP下载断点续传  */ function dl_file_resume($file){       //检测文件是否存在     if (!is_file($file)) { die("<b>404 File not found!</b>"); }           $len = filesize($file);//获

  • python实现可以断点续传和并发的ftp程序

    前言 下载文件时,最怕中途断线,无法成功下载完整的文件.断点续传就是从文件中断的地方接下去下载,而不必重新下载.这项功能对于下载较大文件时非常有用.那么这篇文章就来给大家分享如何利用python实现可以断点续传和并发的ftp程序. 一.要求 1.用户md5认证 2.支持多用户同时登陆(并发) 3.进入用户的命令行模式,支持cd切换目录,ls查看目录子文件 4.执行命令(ipconfig) 5.传输文件: a.支持断点续传 b.传输中显示进度条 二.思路 1.客户端用户登录和注册: a.客户端仅提

  • ASP.NET 文件断点续传实现代码

    这里我通过Response类中的AddHeader方法将一个HTTP头添加到输出流中.在HTTP头中,是由头信息和体信息组成.两者之间用一行空行分开.这里利用在头中加入Range段,来表示客户端希望从何处继续下载,来实现续传功能. 好了废话不多说,让我们开始吧. 1.新建1个主页,名字随便起哈. 2.在该页中添加1个LinkButton按钮,该按钮用来执行实现的过程. 3.在LinkButton的Click事件中,实现断点续传功能. 代码如下: 另外不要忘记引用System.IO命名空间,这里只

  • Java如何实现HTTP断点续传功能

    (一)断点续传的原理 其实断点续传的原理很简单,就是在Http的请求上和一般的下载有所不同而已. 打个比方,浏览器请求服务器上的一个文时,所发出的请求如下: 假设服务器域名为wwww.sjtu.edu.cn,文件名为down.zip. GET /down.zip HTTP/1.1 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms- excel, application/msword, a

  • 让PHP支持断点续传的源码

    比如第一次请求一个文件的从0到999字节,第二次请求1000到1999字节,以此类推,每次请求1000字节的内容,然后程序通过fseek函数去取得对应的文件位置,然后输出. 复制代码 代码如下: $fname = './05e58c19552bb26b158f6621a6650899'; $fp = fopen($fname,'rb'); $fsize = filesize($fname); if (isset($_SERVER['HTTP_RANGE']) && ($_SERVER['H

随机推荐