zoukankan      html  css  js  c++  java
  • [C# 多线程处理系列专题七——对多线程的补充

    因为有些人可能会疑惑,将了这么多多线程,到底在实际的应用上有什么作用的呢? 这里我在这里用多线程简单实现了一个文件的下载的功能。

    服务器端页面:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="FileServer.Default" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>  
        <form id="form1" runat="server">
        <div>
        
        <asp:Image ID="Image1" runat="server" ImageUrl="~/Images/1.gif" />
        
            说明: CLR Via C#
            </div>
            
        </form>
    </body>
    </html>

    服务器页面只是一个简单显示需要下载文件的一些信息,这里通过Handler.ashx来处理文件的下载,把文件的转化为二进制字节写入到输出流中,具体实现代码为:

     public class Handle : IHttpHandler
        {
            public void ProcessRequest(HttpContext context)
            {
                HttpResponse response = context.Response;
                HttpRequest request = context.Request;
                FileStream fileStream = null;
                byte[] buffer = new Byte[10240];
                int length;
    
                // 剩余的字节大小
                // 因为这里采取的是每次写入10240字节到输出流中
                long readToData;
                try
                {
                    string filename = "CLR via CSharp 3rd edition.pdf"; //通过解密得到文件名
    
                    string filepath = HttpContext.Current.Server.MapPath("~/") + "Resources/" + filename; //待下载的文件路径
    
                    fileStream = new FileStream(filepath, FileMode.Open,FileAccess.Read, FileShare.Read);
                    readToData = fileStream.Length;
                    while (readToData > 0)
                    {
                        // 实际读取的字节大小
                        length = fileStream.Read(buffer, 0, buffer.Length);
                        // 把读取到的字节写入输出流中
                        response.OutputStream.Write(buffer, 0, length);
                        response.Flush();
                        readToData = readToData - length;
                    }
                }
                catch (Exception ex)
                {
                    response.Write("Error:" + ex.Message);
                }
                finally
                {
                    if (fileStream != null)
                    {
                        fileStream.Close();
                    }
    
                    response.End();
                }
            }
    
            public bool IsReusable
            {
                get
                {
                    return false;
                }
            }
        }

    这里牵涉到HttpHandle对象问题,这个对象在Asp.net中是真正处理数据的对象,后面如果有时间也和大家分享下深入理解Asp.net系列,主要是介绍在Asp.net中一些核心对象为我们默默做的一些事情,在这里也不详细介绍HttpHandle对象了, 这个示例中主要通过这个类来对文件的处理,把文件的二进制字节写入到输出流中, 客户端在从输出流中读取字节,然后保存为文件(其实文件也就是“流”)。

    客户端:

    客户端建立了一个WinForm窗口,通过WebBrower控件(就是在WinForm程序中显示网页的控件)来连接服务器页面,当按下下载按钮后,通过线程池线程来执行下载方法。主要代码为:

    public void DownLoad(object state)
            {
                // 计时对象
                Stopwatch sw = Stopwatch.StartNew();
    
                HttpWebRequest request;
                HttpWebResponse response;
                Stream stream;
    
                // 下载下来的保存的地址
                string savepath = "D:\\Download.pdf";
                FileStream savestream = new FileStream(savepath, FileMode.OpenOrCreate);
                try
                {
                    // 发出请求
                    request = (HttpWebRequest)HttpWebRequest.Create(url);
    
                    // 获得回应对象
                    response = (HttpWebResponse)request.GetResponse();
    
                    // 获得回应流
                    stream = response.GetResponseStream();
                    byte[] bytes = new byte[10240];
                    int readsize;
    
                    // 每次都读取10240字节
                    // 采用的是同步读取方法
                    // 计算耗费的时间             
                    readsize = stream.Read(bytes, 0, bytes.Length);
                    while (readsize > 0)
                    {
                        savestream.Write(bytes, 0, readsize);
                        readsize = stream.Read(bytes, 0, bytes.Length);
                    }
    
                    sw.Stop();
                    MessageBox.Show("下载耗时为:" + sw.Elapsed.ToString(), "提示");
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Error");
                }
                finally
                {
                    savestream.Close();
                }
            }

    这样就利用线程池线程简单完成了客户端下载服务器端文件的功能,并且使用线程池线程这样不会主线程,从而导致在下载文件时,界面同样可以操作,如果不采用多线程操作的话将会在下载过程导致界面“卡死”现象,这样就会给用户带来不好的用户体验。

    其实本来还想做复杂点的, 开始想实现的功能,是服务器端断点续传,然后客户端多线程下载的功能的,这个示例中只用到了一个线程池线程来完成下载任务,本来想通过执行多个线程池线程来完成下载任务的, 每个线程只负责一部分的读取工作, 然后把每个线程中读取的字节合并起来就是完整的文件字节了,但是这里遇到一个问题,怎么在服务器端实现续传的功能的, 客户端通过AddRange方法来发出部分读取请求,然后服务器端就要对请求头Range进行解析的,实现原理我还是清楚,但是在做的过程中还是出现了问题。所以这里只能分享一个简单的下载文件的功能给大家了, 至于多线程的下载和断点续传和大文件的上传等问题,等我学习了再和大家分享, 如果有大牛可以帮助我解决服务端断点续传的问题的话,欢迎留言。

     源文件下载链接:https://files.cnblogs.com/zhili/FileServer.zip (下载下来后只需要在服务器端Resources文件夹下添加一个文件就可以运行了)

    如果您认为这篇文章还不错或者有所收获,您可以通过右边的“打赏”功能 打赏我一杯咖啡【物质支持】,也可以点击右下角的【店长推荐】按钮【精神支持】,因为这两种支持都是我继续写作,分享的最大动力


  • 相关阅读:
    hihoCoder #1062 : 最近公共祖先·一
    hihoCoder #1050 : 树中的最长路
    hihoCoder #1049 : 后序遍历
    108 Convert Sorted Array to Binary Search Tree 将有序数组转换为二叉搜索树
    107 Binary Tree Level Order Traversal II 二叉树的层次遍历 II
    106 Construct Binary Tree from Inorder and Postorder Traversal 从中序与后序遍历序列构造二叉树
    105 Construct Binary Tree from Preorder and Inorder Traversal 从前序与中序遍历序列构造二叉树
    104 Maximum Depth of Binary Tree 二叉树的最大深度
    102 Binary Tree Level Order Traversal 二叉树的层次遍历
    101 Symmetric Tree 判断一颗二叉树是否是镜像二叉树
  • 原文地址:https://www.cnblogs.com/zhili/p/FileDownLoad.html
Copyright © 2011-2022 走看看