当前位置:首页 > Windows程序 > 正文

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

2021-03-26 Windows程序

标签:

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协议:

二、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 < 0) { from = 0; } long to = this.currentSize + this.step - 1; if (to >= this.totalSize && this.totalSize > 0) { to = this.totalSize - 1; } this.Download(from, to); } /// <summary> /// 下载 /// </summary> /// <param></param> /// <param></param> public void Download(long from,long to) { if (this.totalSize == 0) { 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 = 0; int size = stream.Read(buffer, 0, buffer.Length); while (size > 0) { //只将读出的字节写入文件 fs.Write(buffer, 0, size); readTotalSize += size; size = stream.Read(buffer, 0, buffer.Length); } //更新当前进度 this.currentSize += readTotalSize; //如果返回的response头中Content-Range值为空,说明服务器不支持Range属性,不支持断点续传,返回的是所有数据 if (response.Headers["Content-Range"] == null) { this.isFinished = true; } } } }

项目源码:

三、多线程下载

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/67776.html