zoukankan      html  css  js  c++  java
  • 用HttpListener实现文件断点续传

    断点续传的原理很简单,就是在Http的请求和应答的报文头上和一般的下载有所不同而已。

    普通方式请求服务器上的一个文时,所发出的请求和接受到的服务器如下:

    request header
    Cache-Control: no-cache
    Connection: close
    Pragma: no-cache
    Accept: */*
    Host: localhost

    response header

    200
    Content-Type: application/octet-stream
    Content-Disposition: attachment;FileName=time.pdf

    当服务器支持断点续传时,请求和应答如下:

    request header
    Cache-Control: no-cache
    Connection: close
    Pragma: no-cache
    Accept: */*
    Host: localhost
    Range: bytes=15360-

    response header

    206
    Content-Type: application/octet-stream
    Content-Disposition: attachment;FileName=time.pdf

    两个报文的不同部分已用红色部分标记出来。可以看出:

    1. 客户端报文头中通过Range报文头来标识客户期望的下载位置。
    2. 服务器的应答号为200时表示是从文件头开始下载,而206表示是从文件的特定位置开始传输,客户端从该应答号可以看出服务器是否支持断点续传。

    也就是说,支持断点续传的时候可以从文件任一部分开始下载,而普通的方式只能从文件头开始下载

    要使得服务器支持断点续传,需要解决以下几个问题:

    1。需要判断客户端是否是续传请求,如果是续传请求时,需要获取客户端所需的文件范围。

    从上面的分析可以看到,当客户端为断点传输时,报文头里会增加Range字段,则可以通过如下方式判断是否是断点传输请求。

    string range = request.Headers["Range"];
    bool isResume = string.IsNullOrEmpty(range);

    2。对客户端做正确的应答相应,以通知客户端服务器支持端点续传

    当为断点传输请求时,对客户端的相应号可以通过如下方式设置:

    response.StatusCode = 206;

    3。传送客户端所需正确的内容

    传送客户端所需正确的内容一般需要经过以下几个步骤

    • 通过分析range来获取客户端的文件请求范围。
    • 断点传输请求时,所需的长度比文件的长度短,故需要正确的设置response.ContentLength64属性。
    • 正确传输所需的内容

    代码示例:

    static void ProcessHttpClient(object obj)
    {
        HttpListenerContext context = obj as HttpListenerContext;
        HttpListenerRequest request = context.Request;
        HttpListenerResponse response = context.Response;

        FileStream fs = File.OpenRead(@"f:\123.pdf"); //
    待下载的文件

        long startPos = 0;
        string range = request.Headers["Range"];
        bool isResume = string.IsNullOrEmpty(range);
        if (isResume) //
    断点续传请求
        {
            //
    格式bytes=9216-
            startPos = long.Parse(range.Split('=')[1].Split('-')[0]);
            response.StatusCode = 206;
            response.ContentLength64 = fs.Length - startPos;
            fs.Position = startPos; //
    设置传送的起始位置
        }
        else
        {
            response.ContentLength64 = fs.Length;
        }

        Console.WriteLine("request header");
        Console.WriteLine(request.Headers.ToString());

        response.ContentType = "application/octet-stream";

        string fileName = "time.pdf";
        response.AddHeader("Content-Disposition", "attachment;FileName=" + fileName);
        Stream output = response.OutputStream;

        try
        {
            Console.WriteLine("response header");
            Console.WriteLine(response.Headers.ToString());
            CopyStream(fs, output); //
    文件传输
            output.Close();
        }
        catch (HttpListenerException e) //
    在未写完所有文件时,如果客户端关闭连接,会抛此异常
        {
            Console.WriteLine(e.Message);
            //output.Close(); //
    如果执行此函数会抛异常在写入所有字节之前不能关闭流。
        }
    }

    static void CopyStream(Stream orgStream, Stream desStream)
    {
        byte[] buffer = new byte[1024];

        int read = 0;
        while ((read = orgStream.Read(buffer, 0, 1024)) > 0)
        {
            desStream.Write(buffer, 0, read);

            System.Threading.Thread.Sleep(1000); //
    模拟慢速设备
        }
    }

  • 相关阅读:
    JavaScript 数组
    Function类型
    javascript面向对象(一)
    javascript变量的作用域
    登陆验证
    注册验证
    php类
    二叉搜索树的 查询最小值
    二叉 搜索树查找最大值
    二叉搜索树 中查找是否存在该值
  • 原文地址:https://www.cnblogs.com/TianFang/p/610739.html
Copyright © 2011-2022 走看看