[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進行解析的,實現原理我還是清楚,但是在做的過程中還是出現了問題。所以這里只能分享一個簡單的下載文件的功能給大家了, 至於多線程的下載和斷點續傳和大文件的上傳等問題,等我學習了再和大家分享, 如果有大牛可以幫助我解決服務端斷點續傳的問題的話,歡迎留言。

 

 源文件下載鏈接:http://files.cnblogs.com/zhili/FileServer.zip (下載下來后只需要在服務器端Resources文件夾下添加一個文件就可以運行了)

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM