zoukankan      html  css  js  c++  java
  • C#编程总结(十二)断点续传

    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 < 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 name="url"></param>
            /// <param name="range"></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;
                        }
                    }
                }
            }

      

    项目源码:

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

    三、多线程下载

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

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

  • 相关阅读:
    如何:为 Silverlight 客户端生成双工服务
    Microsoft Sync Framework 2.1 软件开发包 (SDK)
    Windows 下的安装phpMoAdmin
    asp.net安全检测工具 Padding Oracle 检测
    HTTP Basic Authentication for RESTFul Service
    Windows系统性能分析
    Windows Server AppFabric Management Pack for Operations Manager 2007
    Mongo Database 性能优化
    服务器未能识别 HTTP 标头 SOAPAction 的值
    TCP WAIT状态及其对繁忙的服务器的影响
  • 原文地址:https://www.cnblogs.com/yank/p/HTTP-Range.html
Copyright © 2011-2022 走看看