因为有些人可能会疑惑,讲了这么多 多线程,到底在实际的应用上有什么作用的呢? 这里我在这里用多线程简单实现了一个文件的下载的功能。
服务器端页面:
- <%@ 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;
-
-
-
- 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;
-
-
-
-
- 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进行解析的,实现原理我还是清楚,但是在做的过程中还是出现了问题。所以这里只能分享一个简单的下载文件的功能给大家了, 至于多线程的下载和断点续传和大文件的上传等问题,等我学习了再和大家分享, 如果有大牛可以帮助我解决服务端断点续传的问题的话,欢迎留言。
本文出自 “LearningHard” 博客,请务必保留此出处http://learninghard.blog.51cto.com/6146675/1034798